Skip to content

Latest commit

 

History

History
228 lines (128 loc) · 49.9 KB

File metadata and controls

228 lines (128 loc) · 49.9 KB

Implementation status — 2 October 2026

Full installed generated-API inventory — current follow-up

The supplied API-enabled JCB package exposes a larger native form inventory than the original golden-image fixture. On MCP 047c08ee, repeating a complete form contract for each registered method can exceed the inventory worker's 8 MiB output allowance. The enriched inventory and catalogue revision also previously serialized the entire expanded inventory through an 8 MiB canonical-JSON limit. This is an MCP inventory limitation; the generated API files are not a repair target.

This follow-up keeps the worker-output and public request/result limits unchanged. Inventory-only transport shares identical native form contracts by a verified content reference and reconstructs every registered route before catalogue synchronization. Aggregate fingerprints use bounded incremental canonical hashing. Native controller/form provenance, method-specific field policy, component ownership, diagnostics and administrator customization remain part of the inventory. Expanded inventory size and reference counts must also be bounded, with invalid references refused before database changes.

The installed regression uses the exact supplied API-enabled JCB ZIP, verified by SHA-256, and a separate disposable routing plugin rendered by its native JCB compiler. The historical linked webservices plugin was not supplied. All 320 native registrations, 318 form-backed routes, 51 forms and 63 GUID routes must reach the installed joomla:mcp:jcb-sync command. Its actual expanded inventory must exceed the old 8 MiB boundary without padding, while compact IPC stays below it. The test compares every persisted schema/action/binding contract, repeats the real command, and checks existing core definitions, authenticated core forwarding and an administrator customization. This establishes full-size synchronization, not complete native CRUD acceptance. Fixture provenance is in the fixture README.

The first installed run on 394f277 confirmed the actual 111-command inventory was 8,468,079 bytes expanded and 3,336,313 bytes compact. The unnegotiated worker failed with WORKER_OUTPUT_LIMIT; the real command then synchronized all 320 routes, and every persisted contract passed its byte-hash and schema-parser checks on Joomla 6.1.4. Preparation took 4.983 seconds with a 52,428,800-byte fixture peak. The full authenticated action search subsequently exposed a second issue: catalogue refresh retained the previous decoded graph while constructing the next graph, exceeding Apache's 128 MiB limit. Refresh now invalidates the previous snapshot and all dependent indexes/policy caches before rebuilding, publishes only a complete graph, and leaves failed refreshes unable to reuse old authority or definitions. The full installed HTTP search remains an acceptance requirement.

The next installed run on 0802504 passed authenticated discovery of all 320 actions, core API forwarding, native customization and 4,339 full-graph verification checks. It exposed a separate overlap on the second console sync: the command loaded the existing parsed catalogue before entering its independently privileged synchronization branch, retaining it alongside the new inventory, seed and database rows. The sync branch now returns before that unused preload; other console operations keep their normal refresh. The existing full-size second command and customization-preservation assertions remain required under the same 128 MiB hosting limit.

All 32 existing local PHP contract suites passed, along with 43 new isolated-process, type-preservation, fingerprint, corruption, Unicode and expanded-size checks. A separate 23-check, 320-route refresh regression runs under a fixed 128 MiB limit, with a 111,149,056-byte peak; the same fixture fails on the second refresh with the previous code. It also checks current schemas/names, unflagged configuration edits, authority/extension/handler revocation, invalid-row failures and recovery without stale fallback. Composer validation, locked dependency verification, PHP syntax and source-pinned seed reproducibility also passed. Fresh installed golden-image evidence and the PHP/database matrix results are retained in the workflows linked from PR #38; previous green runs do not establish this full-size case.

Generic installed component API contracts — current change

Explicit catalogue synchronization now inspects registered API routes for enabled installed third-party components for which the operator has native administration permission. Joomla core component identities come from the native ExtensionHelper::getCoreExtensions() inventory and are excluded along with the MCP component; the existing Joomla core catalogue and execution contracts remain in place. Extension protected and locked flags do not define this API scope: they govern extension removal or disabling, not API authority. The administrator refresh action and the compatibility command joomla:mcp:jcb-sync synchronize these component APIs alongside the separately inventoried JCB commands. Each component retains its own provider, permission ceiling, registration-plugin dependencies and unsupported-contract diagnostics.

The generic route adapter supports reviewed native CRUD method/task pairs, numeric item IDs, declared GUID aliases and registered unique-key paths. It preserves literal route defaults and bounded nested filter input. It does not infer routes from table names, generate missing endpoints or expose specialized controller tasks without an adapter. Ordinary discovery still reads persisted catalogue rows and performs no synchronization.

FormContracts follows literal installed API-controller/model/form bindings and confines source/XML reads to the installed component. It describes native field filters, defaults, choices, conditional requirements, relationship identifiers and nested subforms, with source hashes. Defaults are descriptive: they are not injected into PATCH data, and omitted update fields remain omitted. Dynamic model validation, custom field rules and runtime ACL remain native API responsibilities. A missing literal form mapping is disclosed; unsafe bound forms are refused rather than guessed.

Only a primary guid explicitly required by the bound create form, without a default, detected native generation or conditional requirement, receives a client-generated UUID. The generated identity is stable for the principal/site/action/idempotency key, disclosed in the plan and frozen with the approved input. Supplied GUIDs are preserved. Relationship GUIDs are resolved from authorized API records and are never invented.

Generated writes freeze their independent read-action revision and require matching typed resource identity on snapshots and read-back. Representation comparisons use only the bound native form's declared integer, boolean and JSON contracts; object/list distinctions, row keys and list order remain significant. Declared request-only controls are reported separately without claiming persistence. Undeclared fields retain strict comparison, and native errors or genuinely unobservable values remain uncertain.

Local validation passed all 32 PHP contract suites: the 27 existing suites plus generated API catalogue (58 checks), transport (86), inventory (18), form-contract (29) and API-verification (126) suites. Source-ZIP installation and relocated-runtime checks passed 1,861 assertions; PHP syntax, source-pinned seed reproducibility, Composer validation and the locked dependency dry run also passed. The new contract suites primarily use router/form/transport fixtures. An additional source inspection of the supplied compiled JCB 6.1.6 package passed 30 form-contract checks and found bindings for 102 controller files covering 51 administrator forms. Neither result is live generated JCB GUID CRUD evidence.

Installed testing exposed an incorrect earlier assumption that protected = 0 identifies third-party components: Joomla's core com_contact can have protected = 0 and locked = 1. Selection now uses Joomla's exact native core identities instead. At source commit f10f390, all seven PR #38 checks passed: two PHP contract jobs, four installed Joomla jobs and one installed JCB golden-image job, across workflow runs 37030966447, 37030966411 and 37030966496. Acceptance evidence is pinned to that source commit; later revisions require their own completed checks.

tests/integration/generated-api.php passed in all five installed jobs. It exercises actual contact webservices registration, an explicitly scoped persisted generic catalogue, an authenticated nested-filter HTTP read, unchanged existing core providers/bindings and native-model cleanup. Its explicit contact scope is an adapter test, not production core selection or live generated-component GUID CRUD evidence.

The separate 2 October isolated test report remains historical installed evidence: 47 of 51 writable JCB families completed CRUD, while components_config, components_dashboard, language_translations and libraries_config returned HTTP 500 through both MCP and the direct native API. Exact exception causes were not captured. Native read-only item redirects and the optional-description compiler crash also remain upstream findings. The current generic changes do not claim to fix these failures, specialized custom-admin tasks or complete API-only JCB parity. Fresh installed acceptance must exercise the current source, GUID routes, nested filters, conditional forms, relationships and strict read-back; phase 2 retains the upstream endpoint/ACL/compiler repairs and their live acceptance.

Native field representation verification follow-up

The fresh installed API audit found three additional representation mismatches. The empty Registry contract now covers params for content, banners, contacts and newsfeeds categories, and images, urls and metadata for articles. It requires the reviewed native write and independent read bindings, and equates only an explicitly approved empty object with an actually empty native Registry representation. Article attribs remains explicitly unobservable when absent from native API read-back. Nonempty, nested, unrelated and malformed values retain strict comparison.

Custom list and checkbox choices are frozen from the authorized field catalogue into the approved plan. Verification compares the exact selected option keys and their frozen labels with Joomla's independent API value-to-label map. It does not rediscover fields during apply or treat an arbitrary returned map as a valid selection. Unknown, additional, missing or changed choices remain uncertain; unsupported or customized contracts retain strict comparison. The existing catalogue authorization, preconditions, independent API reads, leases and replay behavior remain authoritative.

See the verification contract and tests. These changes do not repair or conceal the documented native Joomla API limitations.

Focused validation passed 1,640 write-verification unit checks, 299 custom-field unit checks, 324 installed Registry/group/module checks and 2,327 installed custom-field checks on Joomla 6.1.4, PHP 8.4.26 and MariaDB 11.8.6. All 27 PHP contract suites pass, as do 1,853 source-package and relocated-runtime checks. Installed negative cases inspect Joomla's checkout metadata separately from unchanged content and custom values; native validation errors remain uncertain until the owned test execution is explicitly reconciled.

Native API field verification — issues #22, #23 and #24

ApiWriteVerification defines narrow, action/route/method/transport-bound field contracts. Empty content.categories params objects may match Joomla's empty Registry array representation. User groups compare exact positive group-ID membership sets, including ID-keyed API maps; missing, additional and malformed memberships remain failures. Other fields retain strict JSON distinctions. API response decoding now preserves empty and numeric-key objects instead of collapsing them into lists; native template inheritance accepts the unchanged empty XML-node representation without losing that distinction.

Site and administrator module create schemas explicitly declare integer ordering. Zero or omission means Joomla assigns the next order for the position; a nonzero value requests that exact order. Plans disclose automatic assignment, and verification.nativeOrdering separately reports the generated value only when the native mutation and an independent item read identify the same module and order. Requested zero is never falsely listed as a literal matched field. Customized bindings and genuine mismatches do not acquire broad coercions. Explicit binding schema overrides preserve imported schemas and administrator-owned definitions during seed upgrades.

The original 1 October acceptance passed 656 tests/write-verification.php checks, including negative shape/membership/order cases, binding boundaries, durable execution/lease release and replay without another mutation. tests/integration/write-verification.php then passed 191 installed Joomla 6.1.4 / PHP 8.4.26 / MariaDB 11.8.6 checks: empty/omitted/metadata category controls; blocked single/multiple-group users; site/administrator modules with zero, omitted and explicit ordering in empty/populated positions. Independent database state, returned identity, disclosed/actual order, lease release and unchanged replay were checked. All owned content fixtures were removed through native models, and all 26 pre-existing PHP contract suites passed locally. The follow-up above extends those checks. Exact-commit cross-platform CI remains recorded in the PR.

Explicit bounded catalogue page sizes — issue #26

All eight definition forms use Joomla's native limitbox with showall="false" and explicit sizes from 5 through 500. Legacy zero requests map to 500; unsupported sizes normalize to an offered bounded value. The model persists that effective value in the native list state so the selected label, fetched rows and aligned offset agree. This completes the All-selector boundary left after #20's ordinary navigation fix.

The installed tests/integration/catalogue-page-limits.php passed 5,688 assertions on Joomla 6.1.4 / PHP 8.4.26 / MariaDB 11.8.6. It submits actual administrator HTTP forms for all eight catalogues, with 521-row datasets, every visible option, zero/negative/oversized/unoffered values, search/publication/access/provider filters, empty and one-row cases, state retention and navigation. This is HTTP/DOM evidence, not JavaScript-click testing. Only owned fixtures were created and removed. Both installed CI runners include the suite; exact-commit CI is reported in the PR.

Administrator catalogue pagination — issue #20

This defect belongs to the component's shared administrator DefinitionsModel, used by providers, schemas, actions, bindings, tools, resources, prompts and targets. The model previously read individual filter_* aliases through the model helper before Joomla populated native nested filter/list state. Joomla Registry treats a stored empty scalar as missing; a submitted blank access/provider dropdown then differs from the helper's numeric default and resets limitstart on every page submission. This is independent of MCP action pagination and requires no plugin change.

The native parent now reads and persists SearchTools request state once. The component normalizes effective filter values without another request read, compares them against the previous aggregate filter state, and resets only genuine changes. Search is included in the native active filter fields. Existing query, ACL and ordering rules remain in place, with bounded limits and aligned nonnegative offsets. Operations does not share the duplicate filter defect; its separate correction isolates saved offsets by operation kind and aligns offsets after applying its effective page-size bound.

tests/integration/admin-pagination.php creates three real database pages for all eight definition views and five operation kinds, uses fresh native administrator applications/models with a shared Joomla session, and checks exact row IDs, offsets, limits, filter changes and context isolation. tests/integration/browser-pagination.php authenticates through Joomla HTTP, submits the actual rendered SearchTools controls and native Next/Previous/Start/End offsets, and checks distinct provider pages, page-size changes and genuine search resets. Both suites clean up only their owned fixtures and run in the installed PHP 8.3/8.4 × MySQL/PostgreSQL workflow and JCB golden-image track.

Local Joomla 6.1.3/MySQL execution reproduced the old model's offset-20-to-zero reset in both suites. The corrected models passed 1,208 native administrator request/session checks and 72 authenticated browser checks. All existing local PHP 8.3 contract suites, source packaging/relocation checks and source-pinned seed reproducibility passed. Current-head cross-version, cross-database and JCB CI results are recorded in the linked PR before readiness.

Permanent article deletion verification — issue #18

HTTP article deletion retains its approved item snapshot and, when available, an authorized content.articles.list definition with its action, binding and schema revisions. The target must be visible through an exact-ID collection lookup before deletion. After an accepted DELETE, a missing-item HTTP 500 triggers an independent collection lookup for each native article state (-2, 0, 1, 2). Each response must be a complete, successful exact-ID collection; arbitrary HTTP errors, incomplete metadata, unavailable visibility and a remaining article preserve the uncertain outcome. Joomla's API integer filter converts filter[state]=* to zero, so a wildcard is not accepted as all-state absence evidence.

Verified permanent absence completes the execution and releases its installation write lease through the existing execution lifecycle. A record that remains trashed is not permanent deletion evidence. Replay returns the retained result without a second DELETE. Existing uncertain executions retain their reconciliation requirement; this change does not automatically clear historical leases.

Regression coverage checks absence and retained uncertainty, frozen definition/authorization boundaries, idempotent replay and a subsequent write. Installed HTTP acceptance independently checks the native content table, completed execution and released lease, unchanged replay evidence, then a real follow-up article create/update. Current-head validation results are recorded in the PR before readiness.

Optional runtime path configuration — issue #17

The component's native Options form now normalizes Joomla Registry's null representation of a blank optional path to the empty string accepted by Settings. This applies to both php_cli_binary and artifact_directory. Supplied paths still require the existing absolute-path, filesystem and private-storage checks; other non-string values remain rejected. The console and webservices plugins own neither these fields nor their rule, so this fix belongs solely in the component.

The PHP CLI field description explains that operators may leave it empty when JCB background jobs are unused, including on shared hosting. Blank configuration retains the existing default CLI path and system temporary storage behavior; it does not remove hosting process restrictions.

tests/integration/runtime-options.php loads the installed component form through Joomla's native com_config model, validates omitted/null/empty and supplied paths, saves accepted options, checks the persisted extension parameters and restores the original values. It also checks invalid paths and malformed values. The existing PHP 8.3/8.4 × MySQL/PostgreSQL installed workflow executes this suite. Validation results are recorded in the linked PR after execution.

Runtime regression follow-up — issues #7–#13

All seven reports are addressed on fix/issues-7-13-stable-runtime. The reported v4 wire logs are unavailable; independent reproductions and current-source tests are recorded separately from that historical run.

Issue #11: the SDK queues encoded replies in its session before delivery. The former 1 MiB persistence bound returned false and silently dropped large discovery replies. The encrypted SDK state now has a 12,000,000-byte bound whose base64 envelope fits the existing MySQL MEDIUMTEXT column. Exceeding it raises a bounded JSON-RPC error rather than dropping a reply. php -d memory_limit=128M tests/session-storage.php verifies a queued reply larger than 1 MiB, owner isolation, overflow rejection, preservation of previous state, and a following same-session ping. Installed Joomla 6.1.3 discovery returned complete tool, companion and resource replies of 1,031,828, 528,289 and 1,189,135 bytes respectively in 0.68, 0.29 and 0.29 seconds during the endurance acceptance run.

Issue #13: independent wire checks verify -32601 for unknown methods, -32602 for invalid known-method parameters (including missing/numeric tool names), -32600 for malformed request envelopes and -32700 for parse/nesting failures. String/integer request IDs remain distinct. MCP forbids null request IDs even though base JSON-RPC permits them; malformed-request errors retain null as the unknown response ID. Valid notifications never receive a response, including unknown or malformed method parameters. Both HTTP eras retain their native classifier/header/session checks before error remapping. SDK-era-specific continuation uses ping where supported and tools/list in the modern era where ping is removed. The wire regression suite currently passes 99 checks; installed stdio also exercises both read tools' invalid input forms and a following ping.

Issue #7: the SDK's associative message decoding erased the empty object/list distinction before validation. A component-owned, dispatch-scoped wire adapter retains original JSON types through stdio and authenticated HTTP, then the shared bounded validator checks the advertised schema. Omitted and explicit empty-object inputs succeed through both read tools; arrays, null and scalars are rejected without native execution. Nested empty/numeric-key mappings and legitimate arrays remain distinct through tool and action validation, encrypted plan resolution, deferred job payloads and recorded result replay. Native form data converts to Joomla Table-compatible arrays only at save, after validation and approval binding. Native item models can erase Registry JSON kinds through toArray; read-back recovers the bounded stored kinds only for reviewed readable fields whose values exactly match the already accepted model projection and item identity. Model redaction or transformation stays authoritative, stored lists remain lists, and list pages incur no extra table reads. Regression cases verify exactly one mutation and identical approved input through both synchronous and deferred execution. Original HTTP era/header and request bounds stay authoritative. tests/wire-protocol.php includes actual newline/stdin cases and both HTTP eras; tests/integration/stdio.php verifies both empty-object reads after installation and passed 26 live assertions creating/replaying a native article plan containing empty-object metadata and attributes, with independent read-back, exactly one mutation, update, deletion and continued ping. No vendor source is changed.

Issue #10: independent Joomla 6.1.3 model calls confirm that content-language ordering by lang_id succeeds on a fresh single-language site; ordering by id fails with an ambiguous SQL-column error. The adapter maps the public identifier alias to the physical primary key, uses qualified fields only when the native model approves them, and returns an accurate public identifier. tests/integration/content-languages.php passed 165 assertions on the genuinely fresh single-language installation and a controlled three-language fixture, testing every advertised ordering, independent MCP reads and cleanup back to the original setup. Empty results remain valid; multilingual setup is not required for this read.

Issue #8: persisted source schemas already distinguish empty objects and lists. Associative runtime decoding erased that distinction before tool/action discovery. Schema-only decoding now preserves object mappings, defaults and numeric object keys. Four native empty-input descriptors publish properties as an object. tests/schema-discovery.php passes 88 checks through SDK HTTP tools/list on API and CLI authorities, serialized action search/description and companion capabilities. It also preserves legitimate required/enum/default/examples arrays and independently validates the system.info input schema.

Issue #9: Joomla ListModel rewinds a start offset when the remaining rows cannot fill its native limit. Shared native pagination now reads the total first, returns empty pages at or beyond it, and reduces the native limit only for a partial last slice. Returned metadata retains the requested MCP limit and exact offset. CacheModel's getData and InstallerModel's translated/filtered collection are counted before slicing. Physical extension/update-site identifier ordering keeps persistent-session slices deterministic as extension languages load. Four adapter families have zero/one/multiple-row model coverage. tests/integration/native-lists.php passed 377 assertions on all 13 reported actions in an installed Joomla 6.1.3/MySQL fixture, comparing direct native results with an independent persistent stdio client, including empty filtered datasets and partial/exact/beyond-end pages.

Issue #12: the SDK validator retained fresh schema objects on every call, exhausting a 128 MB process at call 538 in an independent 120-field reproduction. Tool calls now use the shared bounded component validator. Canonical JSON normalization uses static recursion without a self-capturing closure, and discovery selects only the requested catalogue family. The component-owned stdio transport handles fragmented input, bounded oversized-frame draining and output backpressure, with readiness waits preserving the SDK's 50 ms idle session polling cadence; scoped console output sends recoverable and fatal diagnostics to stderr even when inherited error_log points to stdout. Tests exercise actual SDK dispatch, same-process recovery and forced fatal output. Arbitrary plugin writes directly to STDOUT remain the plugin's responsibility.

tests/stdio-endurance.php completes 600 requests under 128 MB with stable allocated memory (35,651,584 bytes after warmup; peak 50,524,160 bytes in the recorded fixture). The installed tests/integration/stdio-endurance.php passes 513 assertions and 600 calls through one PHP process under the same memory limit, with a 10-second deadline per call. On Joomla 6.1.3, PHP 8.3.6 and MySQL, elapsed time was 40.48 seconds and PHP RSS was exactly 66,338,816 bytes at each 100-call checkpoint. This workload covers live reads, discovery, invalid requests and ping; write/reconciliation coverage remains in the separate lifecycle suites. The contract workflow, all four installed PHP/database combinations and JCB golden-image runner include these new acceptance suites.

Overlapping defects are fixed in TypeScript PR #45, tracked by issue #44. Its companion fixes retain wire object/list shapes, publish correct schema maps, preserve exact native pagination and map content-language ordering. PHP SDK session storage, SDK validator retention and the PHP server's JSON-RPC dispatch are implementation-specific and are not asserted as TypeScript SDK defects.

Repository and source baseline

The migration PR #1 and release realignment PR #3 are merged. Original MCP source: 2cff50f4f6b440da3c684f9995a77efad32e1a36. JCB source: extension-builder/joomla@5ee658dd07eb749dca43ed4722f6cca7eb8208cf. The latest component release tag is v1.0.2; this branch records pending fixes under [[[NEXT_VERSION]]] and creates no release tag. OctoJPack selects the tagged component and independent plugins from its fixed configuration and publishes to joomengine/mcp_package.

Package release follow-up

Release run 36543905015 updated and hashed the component feed, then stopped before packaging because GIT_TOKEN was unavailable and VDM_GLOBAL_TOKEN was empty. The .octojpack format matches the native loader; its .global.token error is the fallback for a missing environment token. The workflow now supplies the built-in read-only GitHub token unless GIT_TOKEN is configured. SSH publication still uses the single Git User setup. No published tag or checksum is changed by this fix; package publication remains unverified until the release workflow completes.

The first installed matrix run for PR #6 rejected the console plugin because the old pinned installer required its release major to match the component's. The JCB golden-image run also stopped at console installation. Both workflows now pin console plugin eab466cfb51c9ef51bdb2f18431c2e2fcdafbc3b from plugin PR #4, which checks the supported component minimum independently of the plugin version. Its installed regression tests read the installed plugin manifest, including in the JCB container fixture. Results for this updated pin are recorded in PR #6 after CI completes; the earlier failed runs are not passing evidence.

Implemented server

Custom field creation defaults (upstream issue #42)

Field creation supplies default_value: "" when the caller omits that key, matching Joomla's administrator form and preventing a newly created field from passing a null default into the backend DOM pipeline. The API request builder covers all six reviewed field routes, and the native com_fields Field create action applies the same fallback before preview/save. Explicit defaults, including null, remain caller-owned; partial updates keep their existing behavior. This is a create-time default, not a migration of existing field rows.

Regression coverage includes confirmed API plans and replay, every native field context, explicit values and partial updates. Installed Joomla coverage creates disposable fields through both HTTP and console, inspects persisted defaults, and invokes the real field plugin DOM hook with deprecation failures enabled. Current-head CI supplies the installed evidence before readiness.

Runtime custom field values (upstream issue #38)

The API write path now supports article, content-category, contact and user create/update actions, including typed article plan tools. Published custom field definitions come from the authenticated, authorized fields.*.list action for the matching Joomla context. Planning preserves the strict reviewed core-field schema, normalizes the optional com_fields alias, freezes discovered metadata with the encrypted approved payload, and reuses that snapshot on apply without rediscovery. Describe exposes the site-specific names and field types; callers without field-discovery permission still receive the core schema with an explicit unavailable status. Articles, contacts and users use top-level API field names; categories use Joomla's nested com_fields form group.

Discovery is bounded to 100 pages and 1,000 field records, with duplicate identities/names, malformed or incomplete collections, inaccessible fields/groups and unpublished fields/groups rejected or excluded as appropriate. Unknown, reserved and conflicting form keys remain blocked. A published field colliding with a core or reserved key blocks dynamic discovery for flat API controllers because Joomla can otherwise move that key out of its core form. Null custom values are rejected; supported empty strings/arrays clear values. Joomla retains responsibility for field type/plugin validation, category applicability and field-value ACL. The stock fields API does not expose its only_use_in_subform flag; it is honored when present, and Joomla validates applicability when absent. Read-back compares observable custom values and retains partial/uncertain status when Joomla omits or changes them.

Unicode field slugs and numeric-leading names are supported. Purely numeric names are excluded consistently with TypeScript because PHP associative JSON decoding can lose the object/array distinction; these require a nonnumeric slug. Native console schemas remain unchanged because the upstream request concerns the API transport. tests/custom-fields.php covers generic/typed planning, pagination, metadata, context/access/publication isolation, normalization, wire contracts, read-back and frozen approvals. The installed HTTP suite creates a native published text field, exercises typed article create/update and com_fields, verifies #__fields_values plus native API read-back, and removes both fixtures through their native models. Local PHP 8.3 contract tests pass; PHP 8.3/8.4 CI and installed Joomla checks must complete before readiness. The reporter's live Joomla 6.1 subform scenario still needs testing. See custom field testing for the procedure.

Template style creation now discovers the selected site's or administrator's existing styles through authorized, bounded list/item reads. The native attributes.xml manifest supplies parent and inheritable; the caller cannot supply these hidden fields. Missing templates, invalid or conflicting manifests and cross-client results are refused before a write. The plan freezes the derived metadata and source style identities, and apply repeats the lookup before claiming the execution; a changed source requires a new plan. No template parameters, home flags or titles are copied from existing styles. The same rule applies to child, inheritable parent and independent templates. Local console creation resolves the same metadata from native administrator models and includes the inheritance in the existing preview item snapshot, preserving the imported schemas and binding the metadata to the plan fingerprint. Unit coverage exercises the real permission/plan lifecycle with recording API doubles and both native clients; installed Joomla child-template rendering is a separate required integration check. This is PHP parity for joomla-mcp issue #40.

Menu component identity (upstream issue #39)

The API menu create/update path now includes an approval-bound component-ID persistence step. Joomla's single-item menu GET derives component_id from the link and can conceal an incorrect stored value. Component menu writes first clear the hidden component ID, then read the new effective item, persist its positive native derived ID through one controlled PATCH, and verify the raw stored ID through the menu collection. Clearing first prevents an unknown new component from retaining an old positive ID. Noncomponent menu items retain zero and need no correction PATCH. Callers still cannot supply component_id.

Plans disclose the follow-up and bind the effective link/type/menu/client plus the read/update/list definition revisions. Item IDs and clients are checked before update snapshots or follow-up writes; ambiguous component options and changed targets fail closed. Correction uses the freshly read ETag and a distinct deterministic idempotency UUID. The initial response is retained before follow-up I/O: any later failure preserves the created ID and a durable uncertain execution, so reapplying the same confirmation cannot issue another POST. Collection verification uses fixed bounded offsets and Joomla's supported filter[menutype], including administrator menu main. Hidden/trashed rows, collection failures or mismatches remain uncertain; item GET cannot turn them into verified success.

tests/menu-components.php exercises create, cross-component and partial update, initial/repair failures, masked stored-zero IDs, replay, denied collection reads, client isolation, malformed links, pagination, revoked repair authority and noncomponent writes. The installed menu-components suite verifies actual #__menu.component_id values after HTTP creation and a link change from com_content to com_contact, then removes its fixture through the native menu model. Local PHP 8.3 menu, existing action and planned-lifecycle contracts pass; PHP 8.3/8.4 and installed Joomla/JCB CI must also pass before readiness.

Database catalogue/authorization, schema validation, reviewed API/native handlers, durable permission/plan/execution/audit services, PHP SDK tools/resources/prompts/sessions, authenticated HTTP routing and local console composition are present. Native administrator forms, assets, access/configuration, operational inspection, grant revocation and execution reconciliation are implemented. The component installer preserves operator settings and customized catalogue rows on update. HTTP routing and console plugins are installed and managed independently.

All 36 imported production native PHP files follow the JCB style, with explicit dependency properties and class/member contract documentation. The source map retains original hashes and records the target transformations. The five original sourceOnlyGates remain deliberate upstream diagnostics; they were rejected by the original implementation and are not missing migrated functionality. See migration provenance.

JCB synchronization inspects actual installed route and console registries. CatalogueBuilder persists provider/schema/action/binding/target records; CatalogueSynchronizer applies them through the customization-aware updater and native assets. Synchronization is an explicit administrator action or joomla:mcp:jcb-sync; discovery performs no writes. Missing JCB hides dependent functionality; missing API registration yields no invented routes. Unsupported contracts remain visible in inventory diagnostics without being advertised as successful executable operations.

Synchronization records the native registration-plugin dependencies. Disabling or uninstalling a registering plugin immediately hides its persisted operations. Permission schemas support authorized installed provider scopes such as jcb.execute, while exact scope checks, publication/ACL changes, revocation and one-use consumption remain enforced. Customized administrator schemas are preserved on upgrade.

Schema ownership also protects the effective validation relationship. When an upgrade replaces a tool, action, prompt or binding's input or output schema, a customized installed schema keeps its existing dependant attached to that policy. Explicit ownership, hash-detected edits, custom schemas and missing schema references prevent automatic replacement. A disabled schema continues to make the definition unavailable. Untouched shipped definitions still receive the new schema.

tests/schema-upgrade.php passes 130 before/after/repeated-upgrade checks through the real ToolDispatcher, catalogue, validator and action executor over test-owned storage and recording read transports. Both generic read tools retain a schema-only action/ID restriction; rejected inputs produce no transport call. Binding input/output policies, disabled/missing schemas, an owned schema omitted from the incoming graph and pristine upgrades are covered. The same regression fails against the previous installer because a formerly denied ID becomes accepted after upgrade. The existing tests/catalogue.php invokes this suite in both PHP CI jobs and retains its original 7,786 checks. All 32 local PHP suites, changed-file syntax and checkout/relocated-runtime checks pass with this fix. The complete follow-up CI matrix must pass on the new PR head before readiness.

JCB commands require approved plans. CommandInput freezes supplied/native environment inputs; command/source fingerprints and a JCB definition/configuration snapshot protect against stale execution. Registered native implementations execute in isolated PHP children. Package operations remain writes, including get; a missing native handler is reported rather than counted as successful coverage.

Approval previews show the selected definitions, frozen option layers, repository identity, effects and revision fingerprints from that same immutable preparation. Credentials and server paths remain private. The graph revision guard covers the entire installed JCB definition/configuration graph; remote dependency traversal remains native execution work, not a falsely enumerated preview. API validation errors retain bounded native field/checkout diagnostics, and both local and remote stdio enforce byte limits before ignoring blank frames.

job and artifact state and 0.1.1 MySQL/PostgreSQL migrations support owned asynchronous work. Jobs retain original authority, encrypted frozen payload, one-use worker ticket, execution claim, progress and lease. Cancellation distinguishes never-started work from potentially partial effects; only unstarted queued jobs can be redispatched. Expired/ambiguous work remains uncertain until inspected. Compiler outputs are validated and retained under opaque IDs with size, hash, chunk-integrity and expiry checks.

The administrator Operations screen includes jobs/artifact metadata and cancellation. The joomla_job_* tools expose owned listing, status, cancellation, queued redispatch and bounded artifact reads. An API worker reloads the requesting Joomla user and rechecks authority; it does not become the trusted console owner.

The tracked component source contains production dependencies, installation data and its administrator licence. Source ZIP installation replaces local archive builders. The manual release freezes metadata and tags the component, updates its component-only feed and hashes its tagged ZIP, then OctoJPack publishes the package with that version. The package tag triggers its own feed and OctoShoom workflow in mcp_package. The shared versioned changelog remains here. See RELEASE.md.

The native Octoleo actions use one Git setup and fully concrete .octojpack values. Each extension explicitly selects its latest tag. The component feed has the published 1.0.0 download and its OctoShoom hash. Package automation and its separate feed stay under mcp_package/.github, which native OctoJPack preserves during replacement. The extracted webservices plugin remains independently installed, upgraded and uninstalled; no component runtime changes are needed for feed separation.

The first-package follow-up adds the missing webservices version/feed/OctoShoom workflow and completes the rollout instructions in RELEASE.md. Release both plugins through their manual workflows, then release the component; no hand-edited release metadata is required. Repository secrets and an authorized release run remain deployment setup, not something inferred from green source/installation CI. This follow-up does not create release tags or publish a package.

Historical verified runtime evidence

The following results belong to the recorded September 24 revisions. Their distribution builders have since been removed; they do not certify the current release workflow. Current source/release verification is recorded separately in the release-alignment PR.

Evidence Verified result
Source and behavioural contracts Component 75d9685, run 35983426985, passed PHP 8.3/8.4. Includes 7,218 catalogue checks, 58 protocol checks, 47 JCB contracts, 36 plan-preview checks, 31 preserved native cases and deterministic seed regeneration. All 280 PHP source files passed syntax checks.
Distribution 69 package checks and 14 positive/negative release-metadata checks passed against actual dependency-inclusive component/console/combined archives. Release metadata tests use explicitly synthetic publication URLs; no release was published.
Installed Joomla core Component 75d9685, run 35983426742, passed all four PHP 8.3/8.4 × MySQL 8.4/PostgreSQL 16 combinations on Joomla 6.1.3, including the standalone console plugin and HTTPS client, administrator/HTTP/ACL/native CRUD and standalone/combined install, upgrade and uninstall.
Installed JCB Component 75d9685, push run 35983422644 and PR run 35983427068, both passed completely. Actual platform: Joomla 6.1.3, PHP 8.4.25, MariaDB 11.4.13 inside image tag octoleo/joomengine:6.1.6-php8.4-apache. The image tag is not treated as the observed Joomla version.
Native and remote JCB execution 299 CLI and 288 authenticated HTTPS-client checks; 30 package-roundtrip checks on each track. All 111 installed commands mapped as executable; zero native JCB API routes were registered. Each compiler track generated/downloaded three verified ZIPs; CLI also installed and independently read back all three extensions.
Workers and lifecycle 17 actual database/process claim-race, cancellation and lost-worker/reconciliation checks; 18 installed console checks; seven upgrade checks, 5,430 upgraded-seed checks and 23 uninstall checks in the golden-image evidence. Partial/uncertain effects were preserved and reconciled.
Independent Docker client Client 1ebb989, run 35983558847, passed PHP 8.3/8.4 contracts and nine actual Compose/TLS checks on each image. Installed run 35983558934 passed both PHP versions, with 14 live SDK/executable assertions each.

The inspected golden evidence artifact records console source 3526cae818803a02971374c044a2e2184f1c2c61, client source 72d02491fe80dadc581d3d9d67b1dfbc917d095d and the installed JCB compiler hash. The later client 1ebb989 fixes Compose command selection when a private-CA entrypoint overrides the image entrypoint; it leaves the tested PHP protocol runtime unchanged. Current workflow pins include that correction and the finalized companion documentation. The PR completion checklist records the final-head rerun and readiness status; earlier results never substitute for a failing later run.

Acceptance boundaries and review handoff

  1. The pinned JCB distribution exposes zero native API routes. Native router tests verify adapter mapping, filters, permissions and plugin provenance; they are not live JCB entity API CRUD. A separately installed API distribution must be synchronized from its actual routes, and unsupported specialized contracts remain explicit diagnostics.
  2. All five package families have real native and HTTPS-client roundtrip evidence. The pinned upstream file/folder reset index lacks destination metadata; missing/divergent effects are reported as incomplete, never as verified success. Exact source evidence remains in JCB integration.
  3. The live compiler scenario targets Joomla 6 and tests three output archives, local installation and remote downloads. Native option contracts cover supported targets; the test does not claim every possible target/option combination or JCB on PostgreSQL. The four-platform database matrix covers Joomla core and companion interoperability.
  4. Runtime implementation and installed acceptance are complete for the pinned, exposed capabilities. Human testing/review, merge, deliberate release publication and Packagist registration are separate handoff actions. No merge, release or production deployment has been performed.

Client ownership

The standalone PHP library, remote stdio executable, Docker Compose packaging, private per-site token configuration and Composer delivery belong to joomengine/mcp_client. The server retains its outbound API adapter in admin/src/Http, without a client-package dependency. Shared wire behaviour is recorded in CLIENT-HANDOFF.md.

Private-message planning preconditions

The component-owned joomla.message-owned-record.v1 contract separates pure planning snapshots from the public message GET, which still marks messages read. Only explicitly declared, unchanged shipped bindings and schemas under the local core provider use the native table reader. The actual API identity, canonical origin and API mount must match this installation. All states are read by exact message ID and recipient; both are checked after normal native table observers. Read/write definition revisions and strict resource-change checks remain bound to approval. Custom or unproven configurations retain their existing API path. Mutation and post-write verification remain native API operations, so the separate missing-message HTTP 500 still retains an uncertain execution.

See the snapshot contract and customization boundary for HTTP-only middleware limitations, opt-out and acceptance evidence.

Installed-audit scope disposition

The component fixes in PR #35 address #22, #23, #24, #26 and #30. The remaining audit reports (#25, #27–#29 and #31–#34) are closed as not planned in this repository under the maintainer's clarified scope: their remaining failures reproduce in Joomla's native APIs. They are compatibility context, not outstanding component implementation work or claims of upstream repair.

Native API limitations and component obligations records the observable behavior and the component's verified responsibility for intended requests, honest uncertainty, identity, and idempotent replay. All currently callable operations remain available. No new gate, native error-to- success conversion, automatic retry or Joomla-specific workaround was added.