Skip to content

feat: compiled discovery cache (+ recovered tier2 tokenizer prerequisite)#121

Merged
markshust merged 3 commits into
developfrom
feature/discovery-cache
Jun 12, 2026
Merged

feat: compiled discovery cache (+ recovered tier2 tokenizer prerequisite)#121
markshust merged 3 commits into
developfrom
feature/discovery-cache

Conversation

@markshust

Copy link
Copy Markdown
Collaborator

Compiled Discovery Cache

Sixth and final audit-remediation PR. 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. 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 generated storage/cache/discovery.php and reports per-section counts + the path.
  • discovery:clear — deletes the cache file (idempotent).
  • Boot gate in initialize(): cache is hydrated instead of rescanning only when enabled AND APP_ENV != development AND a valid cache file exists. A missing file → normal rescan; a corrupt/invalid/version-mismatched file → loud DiscoveryCacheException (no silent fallback). Development always rescans (markers take effect immediately).
  • Env vars (read by a core-owned DiscoveryEnvironment, not via marko/config): APP_ENV (default production), DISCOVERY_CACHE_ENABLED (default true; off on 0/false/no/off/empty), DISCOVERY_CACHE_PATH (default storage/cache/discovery.php).
  • Ships packages/core/config/discovery.php (core's first config/) for marko/config consumers.

Architecture

  • marko/core gains NO dependency on marko/config — the boot-time gate reads $_ENV directly (config isn't bound until module-boot callbacks, after discovery). Serialization is a var_export array literal hydrated via new PreferenceRecord(...) etc. — no closures, no unserialize. ModuleManifest (closures) is explicitly not cached.

⚑ Important — included prerequisite fix

This branch also re-implements the tokenizer-based ClassFileParser (Tier 2 F3, the first commit dc0ecc7). That task was reported complete in Tier 2 but its edit never landed on develop (it was lost — most likely a race with the parallel PluginInterceptor worker in packages/core); develop still had the buggy preg_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:cache must run on deploy (after composer install/code changes). A one-line note was added to .claude/release-process.md.

🤖 Generated with Claude Code

markshust and others added 3 commits June 12, 2026 15:06
…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>
@github-actions github-actions Bot added the enhancement New feature or request label Jun 12, 2026
@markshust markshust merged commit ac8ca6b into develop Jun 12, 2026
1 check passed
@markshust markshust deleted the feature/discovery-cache branch June 12, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant