Skip to content

Readiness

An honest checklist of what a core proposal would need. Re-checked on 25 October 2026 against 2.x commit 4239582, tag 2.1.0-beta2. Items that were not re-run say so. Each item is marked done or open, with the file, command or link that shows it. Most items are open. The concerns page argues that the design fits the questions raised in core; this page is about whether the code is ready, and it is not yet. The 25 October check is written up in Findings.

Summary

# Item Status
1 Unit tests of kit output cover every kit open
2 Test suite runs on the current Drupal test stack done
3 Functional tests (form submission, AJAX, nesting) open
4 Known bugs found while writing these docs are fixed open
5 Drupal coding standards open
6 Static analysis (phpstan) baseline open
7 Stable releases of the module and its dependencies open
8 PHP / Drupal version matrix tested open
9 Documented API and BC promise open
10 Dependency on kits and formfactory resolved open
11 No PHP references in kit output done
12 Output is a plain render array that works with existing forms done
13 Memory and time cost measured done
14 Developer documentation done

Details

1. Unit tests of kit output: open

tests/ has 38 test files. 37 are kit tests. CoreVersionRequirementTest checks formfactorykits.info.yml. The Drupal 12 run on 24 October 2026 executed 203 tests. Count the files with:

find tests -name '*Test.php' | wc -l      # 38

grep -rhE 'function test' tests also matches the commented-out testCreateTabsWithOtherKits(), so that count is one higher than the executed suite.

These concrete kit classes have no test class: TableRowKit, TabKit, OptionKit, TaxonomyTermAutoCompleteKit, TaxonomyTermSelectKit, UploadValidatorKit, FileSizeUploadValidatorKit, ImageExtensionUploadValidatorKit, ImageResolutionUploadValidatorKit, ExampleKit, ItemKit, TemplateKit. FileKitTest constructs FileSizeUploadValidatorKit and ImageExtensionUploadValidatorKit. ImageResolutionUploadValidatorKit is only imported, and UploadValidatorKit has no test reference. TextFieldKit and TextAreaKit have test classes. A test of tabs with child kits is commented out in tests/src/Unit/Kits/Container/Tabs/VerticalTabsKitTest.php. No coverage percentage has been measured: on 25 October 2026 neither host PHP nor the PHP 8.5 test image provided PCOV or Xdebug. The module's own core-merge issue #3562924 sets "90%+ Test Coverage" as a remaining task.

2. Test suite runs on the current test stack: done

KitTestBase no longer overrides assertEquals(), and phpunit.xml no longer uses <listeners> or <filter>. On 24 October 2026 the unit suite ran on Drupal 12.0.0-beta2, PHP 8.5.12, PHPUnit 12.5.40, and printed OK (203 tests, 204 assertions). That does not cover Drupal 10.2 or 11, and there is still no CI. See item 8.

3. Functional tests: open

There are no kernel, functional or JavaScript tests. Nothing in the repository submits a form built with kits, rebuilds it through AJAX, or reads it back from the form cache. The claim that kits avoid the failure in #3539320 rests on the output being a plain array (item 11), not on a test.

4. Known bugs: open

Found while writing these docs, each reproduced by running the code:

Bug Where Effect
file() calls an unimported class src/Services/FormFactoryKitsService.php, file() Fixed in 2.1.0-beta2. file() returns ManagedFileKit::create(...).
Legacy upload validator keys src/Kits/Field/Media/ManagedFile/UploadValidators/*.php (CALLBACK constants) #upload_validators uses file_validate_* names; Drupal 11's FileValidator expects constraint plugin IDs such as FileSizeLimit. See File and image kits.
Building is not idempotent Drupal\kits\Kit::getChildrenArray() (dependency) A second getArray() / getForm() on the same kit tree repeats parent IDs in #parents (['outer', 'outer']).
#parents of nested children FormFactoryKit::getArray() with Kit::getChildrenArray() Children of a DetailsKit get #parents = ancestor IDs only, without their own key, so siblings appear to share one value path. Needs a functional test (item 3) to confirm the effect on submitted values.
FormFactory keeps state between loads FormFactoryService (dependency drupal/formfactory 2.1.0-beta3) load() still does not reset the service's kit list, so a second form built in the same request also gets the first form's kits. getForm() no longer throws when no kit has been appended: $form is initialized to [] (0971922).
Getters typed too narrowly ClassAttributeTrait::getClasses(), DescriptionTrait::getDescription() Return NULL where the declared type does not allow it, so calling them before a value is set throws TypeError.
TaxonomyTermAutoCompleteKit::setVocabulary() src/Kits/Field/Entity/TaxonomyTermAutoCompleteKit.php Writes #vid, which entity_autocomplete ignores; it does not limit the vocabulary.

5. Drupal coding standards: open

vendor/bin/phpcs --standard=Drupal,DrupalPractice \
  --extensions=php,module,inc,install,yml src formfactorykits.info.yml formfactorykits.services.yml

Measured on 4 October 2026 and not re-run on 25 October 2026: with drupal/coder (PHP_CodeSniffer 3.13.6) this reports 2,203 errors and 9 warnings in 76 files; phpcbf can fix 2,106 of them automatically. Most are formatting (the code uses 4-space indentation, Drupal uses 2).

6. Static analysis: open

There is no phpstan.neon or baseline in the repository, so no phpstan level is claimed. The implicit-nullable parameters named here on 4 October 2026 are gone. On 25 October 2026 this command printed nothing:

grep -rnE '[(,] *(string|int|array) \$[A-Za-z]+ = NULL' src

7. Stable releases: open

The module's latest tag is 2.1.0-beta2 (git tag). There is no alpha tag. #3562924 still lists an "Alpha release" as a remaining task. The tags that exist are betas. The dependency chain is also beta: drupal/formfactory ^2.1@beta (composer.json). The releases checked on 25 October 2026 are formfactory 2.1.0-beta3, kits 2.0.0-beta5, and query 2.0.0-beta7.

8. Version matrix: open

formfactorykits.info.yml declares core_version_requirement: ^10.2 || ^11 || ^12. The code needs PHP 8.0 features (union and static return types, match, named arguments), and Drupal 10.2 itself requires PHP 8.1. There is no CI configuration in the repository. The unit suite has been run on Drupal 12.0.0-beta2 (item 2). Drupal 10.2 and 11 were not re-run on 25 October 2026. The benchmark ran on PHP 8.3 only and was not repeated for this check.

9. API and BC promise: open

There is no documented backwards-compatibility policy, no @api or @internal markers, and public properties such as $isChildrenGrouped and OptionsTrait::$options are part of the de facto API. A core proposal would need to decide what is public before anything else.

10. Dependencies: open

The module depends on kits:kits and formfactory:formfactory (formfactorykits.info.yml), and through them on query. Core cannot depend on contributed modules, so this must be resolved first. See the merge path for options.

11. No PHP references in kit output: done

grep -rn '&\$' src prints only the two core method signatures in FormObjectBase. See Concerns.

12. Plain arrays and existing forms: done

FormFactoryKit::getArray() returns a new array, and FormFactoryService::getForm() adds kits to the array passed to load(). See Concepts and Altering any $form array.

13. Cost measured: done

Benchmarks measure A (bare arrays), B (the #3525331 wrappers, on a patched core) and C (kits). Against B (28 October 2026), kits retain about 38% less memory, with about 18% higher peak; build time was lower on 500 fields and within noise on 5,000 fields. Against bare arrays every object layer costs more, kits included. Whether that cost is acceptable is for reviewers to judge.

14. Documentation: done

This site, including a reference page for every kit and trait. It is hand-written; keeping it in step with the code is a maintenance task of its own.