Pioneer Compiler Specification

Living Standard,

This version:
https://spec.find.how/
Issue Tracking:
GitHub
Editor:
Find How

Abstract

This document defines the active Pioneer compiler architecture and rules for porting Illuminate and Laravel-style applications to a statically analyzable Deno and edge runtime.

1. Introduction

Pioneer is a compiler-directed architecture for porting Illuminate and Laravel-style applications to Deno-compatible and edge-compatible runtimes while preserving the productive Laravel programming model. This specification defines the private Find How compiler contract: how source files are discovered, how providers declare application capabilities, how kernel entry points become deployable artifacts, and which rules runtime source must satisfy before it is certified.

The numbered rules in Rule Catalog are normative. Sections that describe motivation, examples, or deferred topics are informative unless they explicitly use RFC 2119 language. A Pioneer implementation conforms to this document only when it enforces the normative rules, emits the generated artifacts described here, and rejects source that would require runtime discovery, dynamic container lookup, unsafe public typing, or unvalidated trust boundary flow.

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in [RFC2119].

2. Goals And Non-Goals

Pioneer exists to make Laravel-style applications statically analyzable without flattening their domain model into a generic JavaScript framework. The compiler owns discovery, identity, dependency wiring, validation gates, and deployment shape so application and Illuminate source can remain small, direct, and tree-shakable.

Normative goals:

Non-goals:

3. Terminology

Application source
User-authored modules that are compiled by Pioneer.
Illuminate source
Pioneer-owned ports of Laravel and Illuminate components.
Provider file
A phase-2 entry point imported through @provider/* or @provider-dev/* that declares bindings, aliases, migrations, model features, system environment variables, host configuration, runtime boot specifications, platform bindings, kernel facades, config merges, middleware aliases, and other provider-owned compiler facts.
Kernel entry point
A source file classified by R15 that imports a kernel facade from @find-how/pioneer and makes top-level declarations for HTTP, Artisan, Queue, Schedule, Broadcast, or Event kernels.
Kernel facade collector
A provider-declared compiler module that consumes top-level calls for one kernel facade during the phase-2 late hook and returns kernel-specific TypeGraph records and binding snapshot inputs.
System environment declaration
A provider declaration that names an environment variable, its expected shape, default, secrecy, and validation behavior.
Host configuration declaration
A provider declaration that names a typed configuration key and any declared derivation from system environment variables.
Platform binding
A provider declaration that maps one canonical binding to target-specific implementation modules and execution capabilities.
Consumed-by-DI module
A handler, listener, command, queue job, middleware, service, policy, observer, model feature, or related module that is reached through compiler wiring rather than imported as a kernel entry point.
Bare nominal path
A compiler-normalized ESM module identity without a file extension, such as @app/http/handlers/ListOrders.
Data resource
A compiler-derived identity for a database table, column, index, or related resource, such as db:edge:users or db:edge:users.email.
Binding snapshot
The exact compile-time binding shape available to one kernel entry point after providers, contextual bindings, middleware context augmentation, and destructuring analysis are applied.
Alias namespace
A compiler-owned lookup domain in which an ergonomic name resolves to a single canonical bare nominal path or generated data resource. Alias namespaces are distinct for bindings, middleware, model aliases, table sugar, and any other compiler-defined lookup domain.
Provider key
The canonical provider identity derived from the import-map provider root and resolved provider file. Provider keys are unique within one compilation unit.
Validation gate
A generated or component-owned function that accepts unknown at a trust boundary and either returns typed data or throws an operational error.
Proof certificate
A compiler-generated record that binds a source content hash, compiler tool versions, checked rule set, and pass/fail state to a component or emitted artifact.

4. Conformance Classes

This specification defines multiple conformance classes. A product MAY conform to more than one class. Claims of conformance MUST identify the class and the rule set version used for certification.

Class Required behavior
Pioneer compiler Implements the compilation algorithms, validates all normative rules, emits diagnostics, and produces generated artifacts from source input.
Runtime emitter Produces Deno-compatible, edge-compatible, or target-specific runtime modules whose observable behavior is justified by compiler graph facts.
Provider authoring surface Accepts only provider declarations allowed by R18 and rejects runtime provider discovery or boot behavior.
Application source Uses kernel facades, consumed-by-DI modules, model declarations, and Laravel folder conventions in ways that the compiler can classify statically.
Generated artifact consumer Reads compiler-generated manifests, contracts, TypeGraph records, and proof certificates without treating them as mutable source-of-truth registries.

5. Architecture Overview

Pioneer splits application interpretation into two compiler phases and one runtime emission stage. Phase 1 constructs the canonical module graph. Phase 2 runs in two ordered hooks. The early hook turns provider declarations, system environment declarations, host configuration declarations, runtime boot declarations, platform binding declarations, migrations, model declarations, config, and module metadata into a typed application graph. The late hook processes kernel entry-point files through provider-declared kernel facade collectors and computes their binding snapshots. Emission writes runtime modules, contracts, manifests, TypeGraph records, validation gates, target configuration, and deployment adapters.

The module graph is the root of trust. Any source fact that cannot be derived from Deno-compatible resolution, import maps, provider declarations, migration metadata, or explicit kernel facade calls is not part of the compiled application. Runtime code therefore does not discover providers, scan route files, load a classmap, ask a package manifest for framework metadata, or infer identity from arbitrary strings.

The emitted runtime is allowed to be smaller and more direct than the developer surface. The compiler may inline factories, erase the container, replace facades with direct binding calls, and emit target-owned wrapper classes for stateful or durable runtimes such as Cloudflare Durable Objects and Cloudflare Workflows. These transformations must preserve the public contracts defined by component contracts.d.ts files and parity tests.

6. Compiler Pipeline

The compiler pipeline is deterministic for a fixed source tree, import map, lockfile, compiler version, and external schema inputs.

6.1. Phase 1: Autoload And Module Graph

Phase 1 loads Deno configuration, package/workspace metadata, import maps, and lockfiles. It builds the Deno-compatible module graph, extracts imports and exports, classifies source files, and emits the initial autoload and TypeGraph records. Phase 1 is responsible for resolving extensionless nominal paths and for separating ordinary aliases from provider discovery roots.

6.2. Phase 2: Provider, Data, Model, And Kernel Wiring

Phase 2 consumes provider files and builds the application graph in two ordered hooks. The early hook builds the binding registry, alias map, tag map, migration registry, system environment registry, host configuration registry, runtime boot registry, platform binding registry, config merge map, listener registry, observer registry, policy registry, middleware alias/group registry, publish manifest, contextual bindings, service extensions, data graph, model graph, and generated contracts. Provider declarations are unconditional compile-time facts. There is no provider boot phase.

6.3. Phase 2 Late Hook: Kernel Facade Processing

The late hook consumes kernel entry-point files classified by R15. Provider-declared kernel facade collectors unroll routes, route groups, mounts, resource routes, queue jobs, schedules, events, broadcasts, and Artisan commands. The late hook computes one binding snapshot per entry point, applies middleware context augmentation, validates handler target contracts, and records all resource edges needed by deployment planning. Phase 3 remains only as a source-classification boundary for kernel entry-point files; it is not a separate processing stage.

6.4. Emission

Emission writes only artifacts that are justified by graph reachability. A conforming implementation emits runtime boot modules, kernel adapters, contracts, validation gates, manifests, TypeGraph records, and proof certificates as needed. It may emit separate artifacts for local Deno development, Cloudflare Workers, Cloudflare Durable Objects, queues, scheduled jobs, CLI processes, Durable Object classes, Workflow entrypoint classes, and other target-specific wrappers.

6.5. Source Classification Algorithm

A Pioneer compiler MUST classify every Pioneer-participating source file into exactly one category before phase-2 wiring begins.

  1. If the file is resolved from a @provider/* or @provider-dev/* import-map root, classify it as a provider file and validate it against R18.
  2. Otherwise, if the file imports any kernel facade from @find-how/pioneer and makes at least one top-level kernel declaration, classify it as a kernel entry point and validate it against R15.
  3. Otherwise, if the file is referenced by a provider declaration, kernel declaration, model feature reference, middleware reference, listener registration, policy registration, observer registration, queue registration, command registration, or contextual binding, classify it as a consumed-by-DI module.
  4. Otherwise, if the file is reachable only through ordinary static imports, classify it as a pure internal utility.
  5. If two categories match the same file, the compiler MUST report a source-classification error and MUST NOT emit runtime artifacts for that compilation.

6.6. Provider Discovery Algorithm

A Pioneer compiler MUST discover providers only from import-map entries whose keys match @provider/* or @provider-dev/*. For each provider root, the compiler MUST resolve the root with Deno-compatible resolution, compute a provider key, parse the provider file, and record only top-level declarations from the explicit provider whitelist.

The compiler MUST reject:

6.7. Alias Resolution Algorithm

When source provides a string that is not already a canonical bare nominal path or generated data resource identity, the compiler MUST resolve it through the active alias namespace.

  1. Select the alias namespace from the operation being validated, such as binding lookup, middleware lookup, model lookup, or table sugar.
  2. Find provider declarations that bind the supplied string in that namespace.
  3. If no declaration matches, report an unresolved-alias error.
  4. If more than one canonical identity matches, report an ambiguous-alias error.
  5. Replace the source string with the matched canonical identity in compiler records and emitted artifacts.

The emitted runtime MUST NOT repeat alias lookup unless a target-specific adapter requires a user-facing string for interoperability. Even then, compiler records MUST preserve the canonical identity.

6.8. Binding Snapshot Algorithm

For each kernel entry point, the compiler MUST build a binding snapshot:

  1. Start with globally provided bindings reachable from production providers and the active runtime target.
  2. Apply contextual provider bindings that match the consuming module or kernel entry point.
  3. Apply middleware context extensions in route order for HTTP entry points.
  4. Read destructured parameter names and namespace member accesses from each consumed-by-DI module reachable from the entry point.
  5. Resolve every requested name to a canonical binding or generated data resource.
  6. Report an unavailable-binding error for any requested binding that is not present in the snapshot.
  7. Emit only bindings, modules, validation gates, and adapters that are reachable from the final snapshot.

6.9. Data Resource Identity Algorithm

For each configured database connection, the compiler MUST derive data resource identity from config merges, registered migration directories, migration SQL or schema introspection, and model declarations.

The compiler MUST assign table, column, and index identities using the exact forms defined in Data And Model Resource Model. Table-name sugar MUST resolve to exactly one generated table identity. Ambiguous table sugar, missing migrations, incompatible model table declarations, unresolved model features, and generated contract mismatches are compile-time errors.

7. Runtime Model

Runtime source is intentionally constrained. Components are factories, constants, and plain objects. Instance state is closure state. Public APIs return null for expected absence, throw operational errors for recoverable failures, and throw plain Error for developer errors. Web Standards are the transport base, so request and response abstractions extend platform primitives rather than replacing them.

The emitted runtime must not depend on runtime package scanning, reflection, dynamic class construction, or a mutable global container. It may include compiler-owned wrappers where the target runtime requires a shape not allowed in user source, such as Durable Object classes and Workflow entrypoint classes. Pioneer has no runtime container. It has compiler-emitted runtime code. User source declares facts, factories, handlers, and pure state reconstruction helpers; the compiler owns wrapper construction, hydration, dispatch, durable execution wiring, and target-specific suspension behavior.

8. Provider Model

Providers are compile-time declaration files, not runtime lifecycle objects. A provider imported through @provider/* or @provider-dev/* imports app from .pioneer/autoload.ts, declares facts at top level, exports nothing, and does not import kernel facades. The provider surface centers on app.provide(canonicalPath, target, options?) and an explicit whitelist of declarations for aliases, tags, migrations, listeners, observers, policies, middleware aliases/groups, context extensions, config merges, translations, views, components, publish mappings, contextual bindings, and service extensions. The provider surface also owns the compiler lifecycle namespaces for system environment variables, host configuration, kernel facade entrypoints, runtime boot specifications, and platform bindings. These are compile-time declaration namespaces, not runtime hooks.

Provider declarations must use canonical bare nominal paths or aliases that resolve to canonical paths. Provider-key collisions are fatal because they make provider identity ambiguous. Alias collisions are handled by alias policy and do not replace nominal identity.

The provider API is the only way to extend Pioneer with kernel facades. Pioneer declares its built-in kernel facades through its own provider file using the same app.kernel.facade(...) declaration shape available to the compiler. Third-party kernel facade authoring is reserved for a future spec version unless a conformance class explicitly opts into it.

9. Kernel Entry Points

A kernel entry point self-identifies by importing one or more kernel facades from @find-how/pioneer and making top-level declarations. The kernel facade set is closed: Route, Artisan, Queue, Schedule, Broadcast, and Event. Middleware is HTTP route metadata and module-backed behavior, not a kernel facade.

Entry-point files have no exports. Handler references, middleware references, queue handlers, listener targets, and command handlers resolve through the same canonical identity and alias policy as provider registrations. The compiler rejects kernel entry points that require unavailable bindings or unresolved module-backed targets. Kernel entry-point files are processed by provider- declared kernel facade collectors during the phase-2 late hook; no separate kernel extraction processing phase exists.

10. Binding And Identity Model

Pioneer distinguishes canonical identity from ergonomic names. A module-backed entity is identified by its resolved bare ESM module specifier. A generated data resource is identified by a compiler-generated resource key. Aliases are secondary names declared by providers; they must resolve to exactly one canonical identity in the relevant namespace before they can be used.

Binding access is static. Handlers and other consumed-by-DI modules receive a destructured view of the binding snapshot. Namespace-style and leaf-style access are both allowed when they can be resolved to the same nominal leaves. Dynamic member access, computed binding names, and runtime app.make(variable) are not production constructs.

11. Data And Model Resource Model

Database resources are generated from database config, registered migrations, migration SQL, schema introspection, database manager and driver bindings, and model declarations. Table identities use db:<connection>:<table>; column identities use db:<connection>:<table>.<column>; index identities use db:<connection>:<table>#<index>. Model identities use their bare module specifier.

Models bind to the data graph through Model.table(...) and feature references such as Model.use([...]). The compiler validates model fillable/hidden/cast/scope/feature requirements against generated data contracts and emits model contracts, database contracts, validation gates, TypeGraph resource records, and per-entrypoint resource snapshots.

12. Validation And Error Model

Every external trust boundary has a validation gate that accepts unknown and returns typed data or throws an operational error. Trust boundaries include HTTP request bodies, route params, query strings, system environment variables, host configuration derived from system environment variables, database rows, model hydration, queue payloads, third-party API responses, file reads, and runtime platform events.

Public APIs have three outcome categories. Expected absence returns T | null. Operational failure throws an Error produced by a component-owned error factory declared in contracts.d.ts. Developer error throws plain Error immediately. A single execution path must not conflate absence, operational failure, and invariant failure.

13. Generated Artifacts

A conforming compiler may emit a subset of these artifacts depending on target runtime and graph reachability:

Generated artifacts are compiler outputs. Source code must not treat generated manifests as a second registry that can override module graph facts.

13.1. Artifact Schema Requirements

Generated artifacts MUST be deterministic for the same normalized compiler input. JSON artifacts MUST use stable key ordering when written to disk. Generated TypeScript declaration artifacts MUST be type-checkable without importing runtime source that is not reachable from the same component.

Artifact Required fields or records
autoload.json Compiler version, source roots, import-map roots, resolved modules, module hashes, imports, exports, file classification, and diagnostics summary.
typegraph.json Canonical module identities, generated data resources, bindings, aliases, provider keys, system environment declarations, host configuration declarations, runtime boot declarations, platform bindings, kernel facade declarations, kernel entry points, validation gates, emitted resources, and proof certificate references.
Provider manifests Provider key, provider file, declaration records, alias namespace records, system environment records, host configuration records, runtime boot records, platform binding records, kernel facade records, dependency edges, target runtime applicability, and collision status.
Kernel snapshots Entry-point identity, kernel kind, collector identity, reachable handlers, binding snapshot, validation gates, middleware context extensions, runtime boot requirements, platform requirements, resource dependencies, and emitted adapter kind.
Database and model contracts Connection identity, table/column/index resources, model identity, fillable/hidden/cast/scope metadata, generated create/update/read contracts, and validation gate identities.
Proof certificates Subject identity, content hash, compiler version, tool versions, rule set version, passed rules, failed rules, generated artifact hashes, and invalidation inputs.

Artifact consumers MUST treat unknown fields as non-normative extensions unless the artifact version declares them as required. Artifact producers MUST bump the artifact version when removing a required field or changing the interpretation of a required field.

14. Interoperability Requirements

Two conforming Pioneer compilers processing the same normalized inputs MUST agree on:

Two conforming runtime emitters MAY produce different JavaScript module layouts, but they MUST preserve the same public contracts, validation behavior, error outcome categories, and Laravel parity behavior for the same reachable entry point.

15. Security And Privacy Considerations

Pioneer treats source discovery, generated artifacts, system environment variables, host configuration, database rows, external payloads, and deployment metadata as trust boundaries. A compiler MUST NOT allow unsafe casts, unchecked data hydration, runtime provider discovery, or mutable generated manifests to bypass validation gates.

Generated artifacts can reveal source topology, deployment resources, database schema, model shape, route shape, and private component names. Implementations SHOULD keep generated artifacts inside private build outputs unless explicitly published. This repository is confidential and proprietary; publication of this specification does not grant source, patent, or implementation rights.

16. Rule Catalog

The following rules are active. Rules are grouped by concern for readability, but the rule identifiers are stable and remain the normative reference targets.

16.1. Source Shape Rules

Id Rule
R1 Factory Functions, Not Classes: No class, this, or user-authored new in Illuminate or application code. Factory functions or constants only. Components expose behavior through factory functions that return plain objects with state closed over by closures. Compiler-owned runtime wrappers, such as Durable Object classes and Workflow entrypoint classes, are the narrow exception. Compiler sweeps may mechanically transform legacy classes during porting, and any lost public inference must be restored through R34.
R2 One Export Default Per Module: One method or runtime leaf per file. Folders replace classes, and mod.ts re-exports the folder surface. Laravel PSR-4 parity is represented by import maps, not classmaps or Composer autoload metadata.
R3 Zero Third-Party Runtime Packages: Illuminate runtime source depends only on Deno globals, Deno KV, Deno Temporal, Web Standards, V8 built-ins, and other Illuminate components. Distribution may use supported package specifiers, but provider runtime code must remain statically analyzable and rule-compliant.
R4 Null Out, Both In: Public APIs return T | null, never undefined. Inputs may accept T | null | undefined and normalize absence to null. Defaults use ??; optional three-state input is represented as ?: T | null.
R9 Zero Annotations At Public API Surface And No Unsafe Casts: Runtime source files carry no public API type annotations and no unsafe as T casts. as const and as const satisfies T are allowed. Public contracts come from component contracts.d.ts files through declaration merging, declare module wiring, satisfies, const type parameters, and template-literal parsing. Unsafe casts are tracked as unsafe boundaries and must converge to zero.
R10 No Proxy Anywhere: JavaScript Proxy is forbidden. Static alternatives include predeclared methods, getter maps, Object.defineProperty, and accessor factories. Dev tooling may use V8-native named property handling where the runtime forces it, but production source remains statically knowable.
R11 Illuminate Extends Web Standards: Illuminate Request extends globalThis.Request, and Illuminate Response extends globalThis.Response. ConsoleRequest extends Request by mapping argv into URL/body semantics. Web Standards are the base contract; Pioneer adds ergonomics without replacing them.
R12 Function Scope Properties: A component folder is the namespace. Each file exports one function or constant representing a static leaf, while create factories return plain objects whose instance methods close over shared state. The component contracts.d.ts declares the full namespace type, and the compiler emits only accessed runtime leaves at each destructuring site.
R13 Laravel Folder Conventions Preserved: Laravel folder conventions such as database/migrations/, config/, routes/, and domain folders are preserved. Import maps provide the autoload mapping. There is no classmap and no Composer dump-autoload equivalent.
R16 Types Only In Component contracts.d.ts: All public type contracts live in component-owned contracts.d.ts files. Runtime source files contain no public type annotations, import type, or export type. Contracts files own namespace shape, runtime leaf wiring, registry augmentation, error contracts, driver contracts, taxonomy contracts, and contextual binding contracts.
R24 Native Narrowing Only: No function may declare a value is T or asserts value is T return type. Use native TypeScript narrowing operators directly at the use site: typeof, in, instanceof, Array.isArray, and nullish checks. Array narrowing uses flatMap with an inline conditional rather than filter with a predicate function.
R34 Transition-Safe Factory Conversion: When an exported class-backed implementation is converted to a factory or closure-based leaf, any lost public type inference must be restored in the owning component contracts.d.ts in the same change. A component may not enter an intermediate state where source annotations are removed, class inference is gone, and declaration wiring is absent. The compiler must verify this through inference-gap and component audits before certification.

16.2. Binding And Provider Rules

Id Rule
R5 All DI Through Kernel-Scoped Destructuring From App: All DI flows through kernel-scoped destructuring. Handlers receive a destructured view of the contextually typed app shape, such as ({ request, params, Str, View, session }) => {} for HTTP. Developers do not access app directly in consumed-by-DI modules; the compiler treats handler destructuring as destructuring from app internally and rejects bindings unavailable in the active kernel. Kernel facades establish context through R15, and app remains a compile-time abstraction through R21.
R6 @provider/* Is The Only Import Map Convention: Pioneer recognizes only @provider/* and development-only @provider-dev/* import-map entries as provider discovery roots. The import map is the authoritative provider registry: no glob scan, filesystem fallback, providers array, decorators, runtime registration, package manifest schema, register, or boot. Every provider root resolves to an R18 phase-2 provider file. All other import-map entries are ordinary aliases with no architectural meaning. Provider installation, publishing, dependency ordering, provider-key collision checks, and warnings are compiler-managed from the module graph and installation metadata. Provider-key collisions are fatal because they create ambiguous provider identity; alias collisions are handled by the alias policy, not by treating them as provider identity.
R7 Manager Delegates To Driver Via Host Config: Drivers are provided at full nominal module paths, and the public alias points to the active driver selected by a host configuration key declared through app.host.config(...) per R41. Driver-swap methods inherit Laravel naming, such as connection, store, disk, guard, mailer, or channel, and return new spread objects without mutating the existing manager. Supported access styles are default alias, fluent switch, and direct binding. When a manager’s host config is derived from a system environment variable and the value is known at build time, inactive driver branches are tree-shaken per R31; when it is not known until runtime, the compiler emits only the minimal typed indirection through the generated environment gate.
R8 Facades Are Constant Wrappers: Facades are constant wrappers over app bindings and never use Proxy. A facade resolves a shorthand key to the active driver and may expose testing helpers only: swap(), spy(), fake(), isFake(), and restore(). Layering is Facade > Manager > Default Driver.
R17 Canonical Identity Is Compiler-Owned: The resolved bare ESM module specifier is nominal identity for module-backed entities. Any registerable entity that has a module path uses that bare nominal path as its canonical identity, including events, listeners, middleware, queue jobs, policies, observers, global scopes, model features, query macros, casts, scopes, model bindings, and handler targets. Database tables, columns, indexes, and migration-derived data resources are canonical compiler resources but not container bindings by default; their identities use db:<connection>:<table>, db:<connection>:<table>.<column>, and db:<connection>:<table>#<index>. Arbitrary strings such as UserRegistered, rateLimit, user:create, or users are never canonical identity unless resolved to a canonical module path or generated data resource. String-literal module and data-resource references in registration and resolution APIs resolve through the same compiler graph as static imports and migration-derived resources and must satisfy the required contract at compile time.
R18 Service Providers As Compile-Time Declarations: A provider is a phase-2 entry point imported through @provider/* or @provider-dev/*. It imports app from .pioneer/autoload.ts, imports no kernel facade, has no exports, and contains only unconditional top-level provider declarations. The primary declaration form is app.provide(canonicalPath, target, options?); provider files may also declare aliases, tags, migrations, listeners, observers, policies, middleware aliases via app.middleware.alias, middleware groups via app.middleware.group, context augmentations via app.context.extend, config merges, translations, views, components, publish mappings, contextual bindings, and service extensions when those forms are on the explicit provider whitelist. Provider files may also declare system environment variables through app.system.env(...), host configuration keys through app.host.config(...), kernel facades through app.kernel.facade(...) subject to R36, runtime boot specifications through app.runtime.boot(...), platform bindings through app.platform.binding(...), and platform execution capabilities through app.platform.execution(...). These lifecycle points are compile-time declaration namespaces, not runtime hooks. Model features, query macros, casts, scopes, model method extensions, and model bindings are ordinary module-backed bindings registered through app.provide, not a separate trait or macro registry. Model files consume those features through static literal references such as Model.use([...]), which R26 resolves through provider bindings. Provider registration arguments that name module-backed entities use canonical bare nominal paths or registered aliases per R17/R26/R28/R32. Route middleware usage belongs to R15 kernel entry points. Routes, queues, schedules, broadcasts, and CLI commands also belong to R15 kernel entry points and are collected by R36 kernel facade collectors.
R21 App Is A Compile-Time Abstraction: app is a developer-facing DI specification, not necessarily a runtime object. The compiler may inline factory calls directly at destructuring sites and emit direct function calls in topological order, eliminating the container from runtime output. Stateful and durable targets may require compiler-emitted runtime wrapper code, but that wrapper code is generated from declarations and MUST NOT reintroduce runtime provider discovery, runtime provider boot methods, or dynamic container lookup.
R23 Contextual Bindings At Compile Time: Each kernel entry point receives a statically known binding snapshot based on what the handler destructures. Middleware may augment or refine the snapshot, and contextual provider bindings may override globals for specific consumers. The compiler emits only the final required bindings, services, and modules for that entry point.
R26 Binding Resolution Is Template-Literal Typed: Every string key that references a binding, module path, registerable module-backed entity, model feature binding, query macro binding, model binding, system environment variable, host configuration key, platform target, kernel facade, kernel facade collector, or generated data resource is typed as a template-literal union derived from provider registrations, the module graph, and the compiler-derived data graph. A string argument is either a bare nominal path, a generated data resource identity such as db:<connection>:<table>, a declared system/host/platform identity, or an alias lookup. Non-path strings compile only if a provider-declared alias maps them to a canonical bare nominal path or generated data resource in the relevant alias namespace, or if the receiving API defines a closed literal namespace; otherwise they are compile-time errors. Table-name sugar such as DB.table("users") or Model.table("users") compiles only when it resolves to exactly one active data resource. Model.use([...]) feature references resolve through the provider binding registry. The compiled output always resolves to direct imports or generated data-resource metadata with no runtime lookup. Middleware context augmentations declared in contracts.d.ts merge into downstream handler binding types.
R28 Bare Nominal Paths: All container bindings, job keys, middleware keys, module specifiers, and string-based resolutions use bare nominal paths without .ts, .js, or .mjs extensions. The compiler normalizes extensions internally; the user-facing contract is extensionless.
R29 Module Graph Is Single Source Of Truth: The ESM module graph built from Deno manifests, import maps, and resolved import specifiers is the canonical authority for module-backed identity, container bindings, aliases, member access, and module identity. Data resource identity is derived from database config, registered migration directories, and migration SQL or introspection, all rooted in module graph and provider records. No independent runtime schema registry may redefine data identity, and no separate sub-binding registry duplicates graph facts.
R30 Static-Only Container Access: Container access in handlers, jobs, middleware, commands, listeners, and services must be static. Dynamic member access such as computed property reads or app.make(variable) is forbidden in production and is at least a warning, or an error in strict mode.
R31 Dual Access Style Support With Full Tree-Shaking: Leaf style and namespace style are both supported and must tree-shake identically. Leaf style destructures leaves directly, such as const { when } = app. Namespace style destructures an aggregate, such as const { Conditionable } = app, and member accesses like Conditionable.when() resolve to exact nominal leaf paths through the module graph.
R32 Service Providers Register Aggregate Paths With Aliases: Service providers declare aggregate component paths and runtime leaves at bare nominal paths, using app.provide as the canonical provider declaration surface. Providers then add aliases for ergonomic destructuring with app.alias(canonicalPath, aliasName), such as Conditionable, conditionable, or User. Aliases are ergonomic secondary names only: they never create or replace nominal identity, and only map a short name back to one canonical bare nominal path or generated data resource in the relevant alias namespace. Model aliases such as User map to canonical model module paths such as @app/models/user; table names such as users are ergonomic metadata that resolve to generated data resource identities such as db:edge:users. The provider remains the source of truth for aggregate-to-leaf wiring, and aliases never replace model, feature, table, column, or resource identity.

16.3. Compiler, Kernel, Data, And Validation Rules

Id Rule
R14 Harvest Parity Tests: PHP Laravel parity tests run alongside TypeScript tests to verify that each ported method preserves Laravel behavior. Parity gaps are tracked explicitly rather than hidden behind type conformance.
R15 Kernel Facades As Self-Selecting Entry Points: A file becomes a kernel entry point by importing one or more kernel facades from @find-how/pioneer and making top-level facade calls. The built-in facade set declared by Pioneer’s own provider is Route, Artisan, Queue, Schedule, Broadcast, and Event. Middleware is HTTP route metadata and module-backed behavior, not a kernel facade. Entry-point files have no exports. The compiler processes kernel facade calls during the phase-2 late hook defined by R36, not in a separate phase-3 processing stage. Kernel facade collectors statically extract and unroll route groups, mounts, match/any/resource expansions, schedules, queues, broadcasts, events, route middleware metadata, and commands into kernel-specific TypeGraph records. Registration arguments that name module-backed entities use canonical bare nominal paths or registered aliases per R17/R26/R28/R32. Every Pioneer-participating file must classify as exactly one provider, kernel entry point, consumed-by-DI module, or pure internal utility.
R19 Compiler Phase 1: Autoloader: Phase 1 runs the autoloader pipeline. deno_config loads Deno, package, workspace, import-map, and lockfile data for the compiler. That Deno-compatible configuration feeds deno_graph, which is the canonical resolver and module graph builder using Deno semantics. Source discovery uses import-map roots plus deno_graph reachability when an import map exists, and tsconfig/filesystem discovery when it does not. oxc-parser extracts exports, imports, and source-level metadata from modules after discovery. The CLI emits .pioneer/graph/autoload.json, .pioneer/graph/typegraph.json, and, when requested, .pioneer/graph/autoload.ts and .pioneer/graph/autoload.d.ts.
R20 Compiler Phase 2: Provider, Data, Model, And Kernel Wiring: Phase 2 consumes the phase-1 autoload map and all R18 provider records. It runs in an early hook and a late hook. The early hook builds the binding registry, alias map, tag map, migration registry, system environment registry, host configuration registry, runtime boot registry, platform binding registry, listener registry, observer registry, policy registry, config merge map, publish manifest, contextual bindings, and service-extension composition. The early hook also builds the data graph and model graph from database config merges, registered migration directories, migration SQL or introspection output, database manager and driver bindings, model bindings, model feature bindings, Model.table(...) declarations, and Model.use([...]) references. The late hook, defined by R36 and ordered by R38, processes R15 kernel entry-point files through kernel facade collectors, builds per-entry-point binding snapshots, and records route unrolling, schedule unrolling, queue registration, broadcast channel registration, event listener wiring, and Artisan command registration. Phase 2 emits .pioneer/boot.ts, database manifests, model manifests, generated database contracts, generated model contracts, generated system and host validation gates, kernel snapshots, and TypeGraph edges connecting models, tables, migrations, features, routes, queue jobs, schedules, broadcasts, events, commands, cache keys, responses, platform bindings, and deployed resources, with no provider boot phase and no runtime provider discovery.
R22 Trust Boundaries Require Validation Gates: Every external data entry point must pass through a validation function that accepts unknown and either returns typed data or throws an operational error. Trust boundaries include HTTP request bodies, database results, ORM/model hydration, third-party API responses, system environment variables, host configuration derived from environment variables, queue payloads, file reads, and runtime platform events. System environment reads pass through generated validation gates derived from app.system.env(...) declarations. Host configuration reads pass through generated validation gates derived from app.host.config(...) declarations. Database query results, migration-introspected rows, and model hydration pass through generated validation gates before entering typed application flow. Model create/update calls that receive external input validate against generated create/update contracts before insert or update, and returned rows validate before becoming model row types. No any intermediary or unsafe cast may stand in for validation.
R25 Three-Tier Error Contract: Public APIs have exactly three outcome categories: expected absence returns T | null; operational failure throws an Error instance created by a component-owned error factory function declared in contracts.d.ts; developer error throws plain Error immediately and is not recovered in production code. User-authored error classes are forbidden by R1 unless compiler/runtime-owned. A function must not conflate absence, operational failure, and invariant failure on the same execution path.
R27 Proof Certificates Are Persistent And Content-Addressed: When a component passes rule checks, the compiler records a proof certificate binding module path, content hash, compiler tool versions, and passed rule set. Any source or relevant compiler-tool change that alters the hash invalidates the certificate. The TypeGraph exposes stale certificates for MCP queries and regression tracking.
R33 Stateful And Durable Targets Use Compiler-Emitted Runtime Wrappers: Stateful and durably executing targets, including Cloudflare Durable Objects, Cloudflare Workflows, and long-lived local Deno or Node processes, require compiler-emitted runtime wrapper code that hydrates state, reattaches resources, dispatches to handlers, and coordinates target lifecycle behavior. Users MUST NOT author the wrapper class, Durable Object class, Workflow entrypoint class, hydration constructor, WebSocket reattachment loop, alarm handler, suspension hook, or Workflow run() method for Pioneer-managed kernels. The compiler emits these from app.runtime.boot(...) declarations with state or execution requirements, app.platform.binding(...) and app.platform.execution(...) declarations, and kernel facade collector output. User-authored providers and kernel registration code remain stateless and I/O-free at registration time. Runtime state lives in factory closures and platform-backed persistence, never in user-authored provider boot methods.
R35 Data And Model Resources Are Compiler-Derived Nominal Resources: Database tables, columns, indexes, and model-to-table bindings are compiler-generated resources with stable nominal identities. Table identities use db:<connection>:<table>, column identities use db:<connection>:<table>.<column>, index identities use db:<connection>:<table>#<index>, and model identities use their bare module specifier such as @app/models/user. Database config and registered migrations define the database resource graph. Models bind to that graph through Model.table("tableName") or an explicit connection-qualified form. Model features, casts, scopes, and query macros are ordinary module-backed bindings registered by providers and consumed through static literal references such as Model.use([...]). The compiler validates model declarations against migration-derived table types and feature requirements, then emits database contracts, model contracts, validation gates, TypeGraph records, MCP resources, and per-entrypoint snapshots.
R36 Kernel Facades Are Provider-Declared Late-Hook Collectors: Kernel facades are declared in the phase-2 early hook through app.kernel.facade(canonicalPath, options) per R18. Pioneer’s own provider declares the built-in facades Route, Artisan, Queue, Schedule, Broadcast, and Event through this same API. Third-party kernel facade declarations are reserved for a future spec version; conforming compilers MUST reject app.kernel.facade(...) declarations that originate outside approved Pioneer-owned provider roots unless a separate conformance class explicitly allows them. After all early-hook declarations complete, Phase 2 enters the late hook. Each registered collector consumes top-level facade calls from R15 entry-point files whose facade binding name matches the collector’s registered facade, resolves named targets through canonical identity per R17 and R26, computes binding snapshots per R23, and emits per-entry-point kernel records into the TypeGraph. Application providers MUST NOT register declarations under an undeclared facade.
R37 Kernel Facade Collection Is Deterministic And I/O-Free: Module-level evaluation of an R15 kernel entry point during the phase-2 late hook MUST be pure collection. The following MUST NOT occur at module scope of a kernel entry point or in any function called transitively at module scope from facade arguments evaluated at registration time: file system reads or writes, network requests, database queries, undeclared environment reads, dynamic import() of non-compiler-resolved specifiers, calls to Date.now() or Math.random() whose results affect registration shape, and any operation gated by a runtime platform capability. Handler bodies, listener bodies, queue job bodies, scheduled task bodies, and command bodies are runtime constructs and are unaffected by this registration-time restriction. The compiler MUST detect violations by static analysis, sealed compile-time evaluation, or an implementation-defined combination that produces stable diagnostics for the same input.
R38 Late Hook Topological Ordering: Kernel facade collectors execute in the phase-2 late hook in a topological order derived from the dependsOn list of each app.kernel.facade(...) declaration. The order MUST be deterministic for the same compiler version and normalized input. Cycles among kernel facade declarations MUST be reported as compile-time errors. The built-in facade declarations define the canonical inter-facade dependency graph for the built-in set; Schedule depends on Queue, and Route, Broadcast, Event, and Artisan declare no inter-facade dependencies unless a later rule revision changes their declared provider metadata. Two conforming compilers MUST agree on late-hook execution order for the same input.
R39 Kernel Facade Collector Contract: A module named as the collector of an app.kernel.facade(...) declaration MUST export a single default function that conforms to the compiler-owned KernelCollector contract declared in Pioneer’s generated contracts. The collector receives an immutable view of the early-hook binding registry, alias map, middleware registries, system environment registry, host configuration registry, runtime boot registry, platform binding registry, model graph, data graph, contextual bindings, deduplicated top-level facade calls for the matching facade, and active runtime target. The collector returns kernel records that the compiler writes into the TypeGraph and uses to build binding snapshots per R23. Collector modules MUST be I/O-free per R37, deterministic for the same input, MUST NOT import kernel facades, MUST NOT mutate inputs, and MUST NOT perform dynamic import(). Built-in collectors are subject to the same contract.
R40 System Env Declarations Are The Only Env Boundary: Every read of a system environment variable from application or Illuminate source MUST target a name declared through app.system.env(...). The compiler MUST reject environment reads that do not resolve to a declaration. The compiler MUST generate validation gates per R22 at the env boundary using the declaration’s typed shape, default, required/optional status, and secrecy classification. The compiler MUST emit target-specific representations of declared environment variables, such as Wrangler variables and secrets for Worker targets and environment templates for local targets, and MUST type environment access at call sites as a template-literal union per R26. Untyped or undeclared environment access is a compile-time error.
R41 Host Config Declarations And Env Derivation: Host configuration values MUST be declared through app.host.config(...) and MUST be typed at compile time. A host configuration key MAY declare a derivation from a system environment declaration; when present, the named environment variable MUST also be declared via R40. The compiler MUST resolve configuration values at build time when the derivation chain is build-time-known and MUST emit a minimal runtime indirection through the generated environment gate when it is not. Driver selection in managers per R7 reads only through declared host configuration.
R42 Runtime Boot Specifications: Every binding registered through app.provide(...) MAY have a matching app.runtime.boot(...) declaration that specifies factory module, instance scope, dependency edges, and optional state or execution requirements. Instance scope is one of singleton, per-entry-point, or per-request. Dependency edges participate in deterministic topological initialization before emitted direct factory calls per R21. When state or durable execution is declared, the compiler emits target-specific wrapper code per R33. State reconstruction and suspension helpers MUST be pure at module load, deterministic, MUST NOT import kernel facades, and MUST NOT mutate compiler inputs. Targets that cannot implement a declared scope, state mode, or execution requirement MUST surface that constraint at compile time.
R43 Platform Bindings Resolve By Target: A canonical binding MAY have multiple module-backed implementations declared through app.platform.binding(canonicalPath, perTargetMap). Platform execution capabilities are declared through app.platform.execution(target, modes). The compiler MUST select the implementation for the active deployment target during phase-2 binding snapshot computation. Implementations MUST satisfy the same public contract per R16. A handler that destructures a binding or member the active target cannot expose MUST produce a per-target compile-time error naming the target, unavailable binding, and declaring platform binding. A handler that requires no target-specific binding MUST compile to every declared target whose execution capabilities satisfy the reachable kernel and runtime boot requirements.

17. Examples

17.1. Canonical Identity Examples

Correct canonical path usage:

app.events.listen("@app/events/UserRegistered", "@app/listeners/SendWelcomeEmail");
Queue.job("@app/queues/ProcessOrder", "@app/queues/handlers/ProcessOrderHandler");
Route.get("/orders", "@app/http/handlers/ListOrders").middleware("@app/http/middleware/RateLimit");

Correct alias usage:

app.alias("@app/events/UserRegistered", "UserRegistered");
app.middleware.alias("@app/http/middleware/RateLimit", "rateLimit");

app.events.listen("UserRegistered", "@app/listeners/NotifyAdmins");
Route.get("/orders", "@app/http/handlers/ListOrders").middleware("rateLimit");

Compile error without a registered alias:

app.events.listen("UserRegistered", "@app/listeners/SendWelcomeEmail");

External trigger names, such as route paths, queue broker names, cron expressions, and Artisan signatures, are transport or user-facing metadata rather than canonical module identity.

17.2. Provider And Model Example

app.config.merge("database", "@app/config/database");
app.migrations("@app/database/migrations");
app.provide("@app/models/user", "@app/models/user");
app.alias("@app/models/user", "User");
app.provide(
  "@find-how/auth/model-features/authenticatable",
  "@find-how/auth/model-features/authenticatable",
);
export default Model
  .use(["@find-how/auth/model-features/authenticatable"])
  .table("users", {
    fillable: ["name", "email"],
    hidden: ["passwordHash"],
  });

The compiler resolves @app/models/user to Model.table("users"), the active database connection, db:edge:users, the migration-derived table type, and all feature requirements. User and users remain ergonomic names, not canonical identity.

17.3. Provider Lifecycle Declaration Example

app.system.env("CACHE_DRIVER", {
  kind: "var",
  default: "d1",
  enum: ["d1", "memory"],
});

app.host.config("cache.default", {
  type: "string",
  default: "d1",
  derivedFromEnv: "CACHE_DRIVER",
});

app.kernel.facade("@find-how/pioneer/kernels/route", {
  facade: "Route",
  collector: "@find-how/pioneer/kernels/route/collector",
  dependsOn: [],
  emits: ["http-handler"],
});

app.runtime.boot("@find-how/cache/store", {
  factory: "@find-how/cache/store/create",
  scope: "per-request",
  dependsOn: ["@find-how/database/connection"],
});

app.platform.binding("@find-how/runtime/process", {
  "cloudflare-worker": "@find-how/runtime/process/worker-stub",
  "cloudflare-durable-object": "@find-how/runtime/process/durable-object",
  "local-deno": "@find-how/runtime/process/system",
});

app.platform.execution("cloudflare-worker", ["ephemeral"]);
app.platform.execution("cloudflare-durable-object", [
  "ephemeral",
  "durable-state",
  "durable-attachment",
]);

These declarations are compiler facts. They do not create provider boot methods or runtime lifecycle objects. Pioneer’s own provider uses this same surface for built-in kernel facades.

17.4. Handler Destructuring Example

export default async ({ request, params, User, View }) => {
  const user = await User.find(params.id);
  if (user === null) {
    return View.notFound();
  }

  return View.render("users.show", { user });
};

The handler does not import or access app. The compiler treats the destructured parameter as a request for bindings from the active HTTP kernel snapshot. If User or View are unavailable in that snapshot, compilation fails before runtime.

18. Conformance And Diagnostics

A conforming implementation MUST reject source that violates any active rule. Diagnostics SHOULD name the rule identifier, the offending module, the relevant canonical identity when known, and the smallest actionable repair.

Every diagnostic record emitted to machine-readable output MUST contain:

Field Requirement
code A stable diagnostic identifier, such as PIO-IDENTITY-UNRESOLVED-ALIAS.
severity One of error, warning, or info. Rule violations that make emission unsound MUST be error.
rule The rule identifier when the diagnostic is tied to a rule, or null for infrastructure failures.
source The module path, generated artifact identity, or external schema input that caused the diagnostic.
message A human-readable explanation.
repair A short actionable suggestion when one can be stated safely.

Required diagnostic classes:

The following diagnostic code prefixes are reserved:

Prefix Meaning
PIO-SOURCE Source-shape or source-classification failure.
PIO-PROVIDER Provider discovery, provider declaration, or provider collision failure.
PIO-IDENTITY Canonical path, alias, or generated resource identity failure.
PIO-BINDING Binding snapshot, contextual binding, destructuring, or unavailable member failure.
PIO-KERNEL Kernel facade declaration, collection, late-hook ordering, collection purity, collector contract, or kernel binding snapshot failure.
PIO-SYSTEM System environment declaration, undeclared environment read, or environment validation gate failure.
PIO-HOST Host configuration declaration, environment derivation, or config-driven driver resolution failure.
PIO-PLATFORM Platform binding declaration, target selection, execution capability, or unavailable per-target binding failure.
PIO-DATA Database, migration, model, data-resource, or validation-gate failure.
PIO-CERT Proof certificate, stale artifact, or rule-certification failure.

The following diagnostic codes are required when the corresponding condition is detected:

Conformance tests SHOULD include harvested Laravel parity tests, static rule fixtures, generated-artifact snapshots, TypeGraph edge checks, and end-to-end kernel emission tests for each supported runtime target.

Each normative rule SHOULD have at least one positive fixture and one negative fixture. Negative fixtures SHOULD assert a stable diagnostic code, rule identifier, and source location. Generated-artifact snapshot tests SHOULD ignore non-semantic ordering only when the artifact format explicitly allows it.

19. Deferred Topics

The following topics are not active rules in this version:

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

References

Normative References

[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119