Skip to content

docs/api: README showcases Core::$executor / Core::$compiler as consumer API while AGENTS.md declares them off-limits; AbstractModule::getGlobals() returns raw CData #192

Description

@lisachenko

Contradiction 1: the engine-global wrappers

AGENTS.md ("Public APIs never leak CData") states that Core::$executor / Core::$compiler / Core::$modules are "core-layer state and not a consumer API". The README, however, documents them as the public way to do things:

  • "The object store" → Core::$executor->objectStore[spl_object_id($instance)]
  • "Abstract Syntax Tree" / "Debugger-grade introspection" → Core::$compiler->parseString(...), Core::$compiler->setOptions(...)

One of the two is wrong. Either:

  • (a) the README routes through named public methods (Core::parseString(), Core::objectStore() or similar facades), and the statics get de-emphasized, or
  • (b) AGENTS.md carves out the specific read paths it blesses for consumers (parse, object-store read) while keeping mutation core-only.

A related structural note: PHP 8.4 asymmetric visibility does not apply to static properties, so public private(set) static is not an available fix — hardening the statics means accessor methods (BC-affecting) or documentation.

Contradiction 2: module globals

src/EngineExtension/AbstractModule.php:233final public function getGlobals(): ?object with @return \FFI\CData|null. AGENTS.md: modules "must expose pure PHP-native interfaces: no public method of a module may return CData". The README's extension example ($globals = $module->getGlobals(); // FFI-backed) is the documented entry point for the whole subsystem, so this is the contract's flagship counter-example. Resolution options: a typed globals-wrapper object, or a documented, explicit exception in AGENTS.md.

Also in scope

@internal marking on the CData escape hatches is inconsistent (tracked separately, but the resolution here should set the rule): StringEntry::getRawValue(), ObjectEntry::getRawValue(), ReflectionValue::getRawValue(), ReflectionClassConstant::getRawValue(), ClosureEntry::getRawFunction(), ResourceEntry::getRawData(), OpLine::getHandler() and ReflectionExtension::getGlobals() all hand out raw CData/pointers without the @internal marker that HashTable::getRawValue() / ReflectionClass::getRawValue() carry.

This is a design decision for the maintainer, not a mechanical fix — filing for discussion. Found during the 2026-08 modernization review.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions