Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b8017c2
docs: tighten framework contribution guidance
binaryfire Jul 28, 2026
83f7ad8
docs: mark Laravel differences guide for deletion
binaryfire Jul 28, 2026
ee66db2
fix(config): replay package merges after worker reload
binaryfire Jul 28, 2026
7e10505
feat(cache): add shared serializable class policy
binaryfire Jul 28, 2026
097adac
feat(cache): apply class policy to array stores
binaryfire Jul 28, 2026
7584ebb
feat(cache): apply class policy to database stores
binaryfire Jul 28, 2026
73f7c40
feat(cache): apply class policy to file stores
binaryfire Jul 28, 2026
c1d4efa
feat(cache): apply class policy to Redis stores
binaryfire Jul 28, 2026
c9e431e
feat(cache): apply class policy to storage stores
binaryfire Jul 28, 2026
b801e88
feat(cache): install global serializable class policy
binaryfire Jul 28, 2026
67eecdf
feat(cache): finalize class policy at process startup
binaryfire Jul 28, 2026
02d5172
fix(cache): normalize stack layers for inspection
binaryfire Jul 28, 2026
eb40bdd
feat(cache): validate model cache stores
binaryfire Jul 28, 2026
bcd2dc5
build(auth): declare cache lifecycle dependencies
binaryfire Jul 28, 2026
efbdba2
feat(auth): validate cached Eloquent providers
binaryfire Jul 28, 2026
a5034d8
feat(auth): register cached user models at startup
binaryfire Jul 28, 2026
8b4fa4e
test(auth): cover serialized user graph caching
binaryfire Jul 28, 2026
6c62d3f
test(auth): cover automatic policy with cache tags
binaryfire Jul 28, 2026
f2ec671
test(auth): cover native Redis model serializers
binaryfire Jul 28, 2026
313c36f
build(sanctum): declare worker lifecycle dependency
binaryfire Jul 28, 2026
17695d7
fix(sanctum): centralize the default token model
binaryfire Jul 28, 2026
3d55835
feat(sanctum): register cached identity models
binaryfire Jul 28, 2026
979fc08
fix(sanctum): keep token caches coherent
binaryfire Jul 28, 2026
2a0b71c
fix(sanctum): reuse the resolved tokenable
binaryfire Jul 28, 2026
b0ef1c0
fix(cache): invalidate every failover store
binaryfire Jul 28, 2026
2d990cf
docs(cache): explain serialized class policy defaults
binaryfire Jul 28, 2026
50dcd31
docs(cache): document serialized object caching
binaryfire Jul 28, 2026
3751a11
docs(auth): explain cached model requirements
binaryfire Jul 28, 2026
4e25399
docs(auth): document user cache serialization
binaryfire Jul 28, 2026
6101859
docs(auth): update cache configuration guidance
binaryfire Jul 28, 2026
f75407a
docs(sanctum): explain identity cache behavior
binaryfire Jul 28, 2026
11c42c5
docs(sanctum): document serialized token caching
binaryfire Jul 28, 2026
319537b
docs(sanctum): clarify tokenable cache staleness
binaryfire Jul 28, 2026
5e219b6
Merge branch '0.4' into fix/cache-serializable-class-policy
binaryfire Jul 28, 2026
7eb69f9
test(cache): tighten serialized policy coverage
binaryfire Jul 28, 2026
216cfd6
docs(cache): record serialized class policy design
binaryfire Jul 28, 2026
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
10 changes: 6 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Anything found follows When to Stop and Report — "the task didn't ask me to fi

1. Read the related Hypervel APIs and tests. Check Laravel or the package upstream for an established public API and behavior.
2. Decide which state is local, coroutine-scoped, or worker-scoped before writing code — see Coroutine and Worker-Lifetime State.
3. Keep Laravel API parity unless Hypervel's runtime requires a deliberate difference. Record intentional differences as described under Porting rules.
3. Preserve Laravel API parity unless it conflicts with a concrete Hypervel architectural constraint, preserves a verified defect, or forces a workaround for an approved enhancement. Any difference requires user approval before planning or editing.
4. Test the public behavior, failure paths, coroutine isolation, and cleanup the feature needs.
5. Complete the verification order below.

Expand Down Expand Up @@ -163,7 +163,7 @@ Build complete, long-term solutions, not MVPs or local workarounds. A broad chan
- **No arbitrary string lengths** — use `->string('name')`, not `->string('name', 100)`. Don't invent limits; specify a length only when the domain or protocol defines one — exact (UUID: 36, ULID: 26, sha-256 hex token: 64) or a defined maximum (IPv6 address: 45).
- **No database enums** — use string columns plus PHP enums. Adding a value to a database enum requires a migration.
- **Prefer `timestamp` over `timestampTz` in migrations** — store times in UTC with plain `timestamp` columns, matching the normal convention in Laravel and Hypervel first-party migrations. Reserve `timestampTz` for columns that genuinely need database-level timezone semantics, such as integrating with an existing timezone-aware schema or columns written by clients in different session timezones. The schema API supports both — this is a column-choice convention, not an API restriction.
- **Guard optional event dispatches with `hasListeners()`** — before constructing and dispatching framework events, guard them with `hasListeners()` so hot paths skip event overhead when nobody is listening. Do not guard dispatches where dispatching is the side effect, such as jobs, broadcasts, webhooks, or command bus calls.
- **Guard optional event dispatches with `hasListeners()`** — before constructing and dispatching framework events, guard them with `hasListeners()` so hot paths skip event overhead when nobody is listening. Bare `*` listeners are passive observers and do not count; targeted wildcards do. Do not guard dispatches where dispatching is the side effect, such as jobs, broadcasts, webhooks, or command bus calls.
- **Use `Sleep::usleep()` / `Sleep::sleep()` for delays in source code** — `Sleep` is fakeable in tests. Use raw `sleep()` / `usleep()` only where real time must pass, such as test harnesses and external-process polling.
- **Use `xxh128` for internal non-cryptographic hashing** — cache and context keys, content checksums, and change detection. It is faster than `sha256`, which is reserved for trust boundaries: stored credential digests, signatures, and anything an attacker gains by forging. Seed it when the hashed value comes from user input, as `SwooleStore` does for its physical table keys.
- **Use immutable dates by default** — Hypervel defaults to `Hypervel\Support\CarbonImmutable`, including where Laravel uses mutable Carbon. Create public or application-configurable dates through the `Date` facade or date helpers, and use exact `CarbonImmutable` for framework-owned internal or held values. Type configurable Carbon boundaries as `CarbonInterface` and native or third-party boundaries as `DateTimeInterface`. Capture the return value of every date modifier whose result must persist. Use `Hypervel\Support\Carbon` only for explicit mutable opt-out or conversion behavior.
Expand Down Expand Up @@ -449,6 +449,8 @@ Examples: `tests/Inertia/CoroutineIsolationTest.php`, `tests/Container/Coroutine

`request()` resolves from `RequestContext` — when no request exists in context (tests that don't make HTTP requests), each `request()` call creates a throwaway fallback instance. This means `request()->merge()` has no effect on subsequent `request()` calls. Replace `request()->merge(['key' => 'value'])` with `RequestContext::set(Request::create('/?key=value'))` to seed a stable request in context.

Seed application requests with `RequestContext::set()`; replacing the `'request'` binding with `instance()` bypasses coroutine-local behavior.

### Static state and test cleanup

`AfterEachTestSubscriber` handles framework-global cleanup between tests. It calls `flushState()` on framework classes that hold static state, and resets the container itself — `Container::flushState()` + `setInstance(null)` — plus `CoroutineContext::flush()`, with each test in a fresh coroutine. So container singleton/auto-singleton instance state and coroutine context don't leak between tests; only `static`/process-global state and live external resources need package cleanup, not mutable state on a container-cached instance. Do not duplicate framework-static resets in `tearDown()`; `AfterEachTestSubscriber` is their one authoritative registry. Tests still own resources they create, such as child coroutines, subscribers, processes, sockets, and temporary files, and must close or join them through exception-safe cleanup.
Expand Down Expand Up @@ -697,7 +699,7 @@ When porting Laravel packages, whether first-party or third-party, keep them as
- Not porting deprecated upstream code or backwards-compatibility shims for versions/features Hypervel does not support — Hypervel is a new framework with no backwards-compatibility burden, so deprecated APIs and compatibility code that exist only to support older versions should be omitted rather than ported. Here, "upstream" means the framework or package being ported, not one of its dependencies — a Symfony deprecation does not make a Laravel API deprecated while Laravel still retains it. If a deprecated upstream surface still contains behavior that Hypervel actively needs, keep the behavior but move it onto the correct non-deprecated Hypervel-owned surface instead of porting the deprecated alias/wrapper as-is
- General performance improvements — but STOP and explain the opportunity to the user first for approval

Hypervel has no obligation to preserve behavior from earlier Hypervel versions, but compatibility with the Laravel public APIs that Hypervel intentionally supports is a current design requirement. Do not use the lack of a backwards-compatibility burden to rename, remove, or change the meaning of those APIs. Propose genuinely different behavior as a distinct Hypervel API; do not hide it inside a Laravel-shaped API.
Hypervel has no obligation to preserve Hypervel-specific behavior from earlier versions, but supported Laravel APIs—including named arguments and protected extension points—must remain compatible unless the user approves a difference under the API-parity rule above. If a Laravel API appears unsuitable for Hypervel, STOP, explain why, and obtain approval before planning or editing. Hypervel's lack of backwards compatibility constraints is not a reason to rename, remove, or change Laravel APIs.

Approved adaptations take precedence over upstream fidelity. Preserve Laravel upstream naming, structure, and style everywhere else.

Expand Down Expand Up @@ -760,7 +762,7 @@ When ported code adds a provider or listener, wire providers and aliases in both
Keep everything else: behavioral descriptions, `@see` links, `@throws` annotations, warnings, contract explanations, usage notes.
Modernize the title line to imperative form ("Returns" → "Return", "Retrieves" → "Retrieve") but do not remove or rewrite the body content beneath it.
Translate non-English comments to English and fix grammar errors.
- **Record intentional Laravel differences where future ports will look** — When a Laravel feature is intentionally not ported because it does not fit Hypervel's Swoole/coroutine architecture, or because Hypervel has a better native equivalent, record it in three places so a future port cannot miss it: (1) the package README under `Differences From Laravel`, with the reason and what to use instead; (2) a concise source comment at the natural insertion point where the skipped method/class would otherwise sit; (3) a concise `REMOVED:` comment at the matching upstream test location when tests are skipped. This is a narrow exception to the "don't annotate divergences" rule: it applies only to intentionally omitted methods or features, never to ordinary ported-and-adapted code. Closed decisions only — real gaps still worth doing go in `docs/todo.md`.
- **Record intentional Laravel differences where future ports will look** — When a Laravel feature is intentionally not ported because it does not fit Hypervel's Swoole/coroutine architecture, or because Hypervel has a better native equivalent, record it in three places so a future port cannot miss it: (1) the package README under `Differences From Laravel` only for differences humans or LLMs using the package need to know or act on, with the reason and what to use instead — internal differences and fixes do not belong there; (2) a concise source comment at the natural insertion point where the skipped method/class would otherwise sit; (3) a concise `REMOVED:` comment at the matching upstream test location when tests are skipped. This is a narrow exception to the "don't annotate divergences" rule: it applies only to intentionally omitted methods or features, never to ordinary ported-and-adapted code. Closed decisions only — real gaps still worth doing go in `docs/todo.md`.
- **Replace framework names in code** — any occurrence of the word `laravel` or `hyperf` in ported code (string literals, comments, prefixes, identifiers, etc.) must be replaced with `hypervel`, preserving the original casing. For example: `laravel_reserved_` → `hypervel_reserved_`, `LaravelExcelExporter` → `HypervelExcelExporter`, `HYPERF_VERSION` → `HYPERVEL_VERSION`. This does not apply to namespaces (which have their own conversion rules) or to references that describe the upstream source (e.g., docblock `@see` links to Laravel/Hyperf source).
- **Don't copy Laravel/Hyperf-specific framework details just to stay 1:1** — keep the behavior the same, but if something only exists because of the upstream framework's own packages, providers, bootstrap system, or architecture, translate it to the Hypervel equivalent or STOP and ask if there isn't one.

Expand Down
3 changes: 2 additions & 1 deletion docs/ai/differences-vs-laravel.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- DO NOT ADD NEW ENTRIES TO THIS FILE. It is queued for deletion. -->

# Hypervel vs Laravel — Differences

Write Hypervel apps like Laravel apps, except for these differences. Most stem from Hypervel running on Swoole coroutines: long-lived workers, no per-request bootstrap, many concurrent requests per worker process.
Expand Down Expand Up @@ -25,7 +27,6 @@ Write Hypervel apps like Laravel apps, except for these differences. Most stem f

- Workers are long-lived; many requests run concurrently as coroutines inside one worker process.
- Anything on a static property or singleton service is shared across all concurrent requests in that worker — treat it like global state.
- Routes retain caller-supplied closures, invokable objects, and object-method callables for the worker lifetime. Prefer `[Controller::class, 'method']` when the container should control the controller's singleton, scoped, or transient lifetime.

## Per-request state

Expand Down
Loading