feat: compiled discovery cache (+ recovered tier2 tokenizer prerequisite)#121
Merged
Conversation
…ed tier2 F3) Tier 2 task 003 (token_get_all parser) was reported complete but its edit was lost before the tier2 commit — develop still had the buggy preg_match parser that matches 'class' in docblocks/strings and misses interfaces/traits/enums. Re-implemented here because it is the HARD prerequisite for the compiled discovery cache (a cache compiled against the buggy parser would permanently bake in silently-skipped files). token_get_all scan: tracks T_NAMESPACE, detects T_CLASS/T_INTERFACE/T_TRAIT/T_ENUM, skips ::class and anonymous classes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verified the tokenizer prerequisite is present; pinned DISCOVERY_CACHE_ENABLED false-set coercion, the corrupt-cache exception path (names the file path, write() throws notWritable), the version-from-constant invariant, four independent boot forks preserving subsystem ordering (observers before dispatcher, commands after module-repo), and mandatory $_ENV + temp-file test isolation. Corrected the task table (002 depends on 001). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…st scan Eliminates the per-request, full-codebase PHP-file scan for #[Preference]/ #[Plugin]/#[Observer]/#[Command] markers in Application::initialize() outside development, via a CLI-compiled cache. All 6 tasks, TDD, full-suite green (6735). - DiscoveryEnvironment: core-owned $_ENV reader (APP_ENV / DISCOVERY_CACHE_ENABLED / DISCOVERY_CACHE_PATH) — NO marko/config dependency (core requires only php + psr/container; config isn't bound until after discovery). - DiscoveryCache: write/read/exists/clear a generated storage/cache/discovery.php (var_export array literal, no closures/unserialize); hydrate back into the four result value objects; loud DiscoveryCacheException (names the path) on corrupt/ invalid/version-mismatched content; write() throws notWritable on failure. - DiscoveryCompiler: runs the four existing discovery passes over resolved modules and produces the plain-array payload (equivalence-tested vs a fresh scan). - discovery:cache (compile + write, reports counts + path) and discovery:clear (idempotent delete) commands. - Boot gate in initialize(): cache used only when enabled AND env != development AND a valid file exists (four independent forks preserve subsystem ordering; CommandRegistry/Runner wiring runs on both scan and cache paths); a missing file rescans, a corrupt file throws. core gains NO marko/config dependency. - Ships core's first config/discovery.php for marko/config consumers. Prerequisite recovered first (commit dc0ecc7): the tokenizer-based ClassFileParser (tier2 F3) whose edit was lost — a cache compiled against the buggy preg_match parser would have baked in silently-skipped files. NOTE: no mtime invalidation — discovery:cache must run on deploy (release note added). Devil's-advocate-reviewed, standards-enforced, docs updated, lint clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Compiled Discovery Cache
Sixth and final audit-remediation PR. Eliminates the per-request, full-codebase PHP-file scan for
#[Preference]/#[Plugin]/#[Observer]/#[Command]markers inApplication::initialize()outside development, via a CLI-compiled cache. 6 TDD tasks, full suite green (6735 passing, 0 failures). Built on Tier 1-5.What it adds
discovery:cache— compiles attribute-marker discovery into a generatedstorage/cache/discovery.phpand reports per-section counts + the path.discovery:clear— deletes the cache file (idempotent).initialize(): cache is hydrated instead of rescanning only when enabled ANDAPP_ENV != developmentAND a valid cache file exists. A missing file → normal rescan; a corrupt/invalid/version-mismatched file → loudDiscoveryCacheException(no silent fallback). Development always rescans (markers take effect immediately).DiscoveryEnvironment, not viamarko/config):APP_ENV(defaultproduction),DISCOVERY_CACHE_ENABLED(defaulttrue; off on0/false/no/off/empty),DISCOVERY_CACHE_PATH(defaultstorage/cache/discovery.php).packages/core/config/discovery.php(core's firstconfig/) formarko/configconsumers.Architecture
marko/coregains NO dependency onmarko/config— the boot-time gate reads$_ENVdirectly (config isn't bound until module-boot callbacks, after discovery). Serialization is avar_exportarray literal hydrated vianew PreferenceRecord(...)etc. — no closures, nounserialize.ModuleManifest(closures) is explicitly not cached.⚑ Important — included prerequisite fix
This branch also re-implements the tokenizer-based
ClassFileParser(Tier 2 F3, the first commitdc0ecc7). That task was reported complete in Tier 2 but its edit never landed ondevelop(it was lost — most likely a race with the parallelPluginInterceptorworker inpackages/core);developstill had the buggypreg_match('/class\s+(\w+)/')parser that matches "class" in docblocks and misses interfaces/traits/enums. Since a cache compiled against that buggy parser would permanently bake in silently-skipped files, the tokenizer is a hard prerequisite and is fixed here first. Worth a look in case you want it backported/noted separately.Operational note
No mtime invalidation by design —
discovery:cachemust run on deploy (aftercomposer install/code changes). A one-line note was added to.claude/release-process.md.🤖 Generated with Claude Code