feat(tools): create_page_draft — the sixth writer creates a hidden page (ADR-180) - #832
Conversation
The backend assistant could draft a content element and a translation but had no way to create the page they would go on. create_page_draft creates ONE standard page under a parent page: always hidden, always in the default language, with title, navigation title and position as the whole field set; the URL segment is left to the DataHandler. It follows the five existing writers to the letter: disabled by default, editing group, NON_IDEMPOTENT_WRITE, approval before every call, preview at suspend, DataHandler under the acting user's PAGE_NEW permission, read-after-write, and a refusal vocabulary that never confirms a uid. ADR-146 named "a sixth writer" and "more than one record per call" as its revisit triggers; both fired, because the obvious shape was "page plus first element in one call". ADR-180 keeps the one-record rule: the tool creates the page and nothing on it, and hands the model the new uid for create_content_element_draft. ADR-146 carries the Amended field. Two things the functional tests taught: the DataHandler's permission check on a NEW page reads sys_language_uid from the incoming record, so the tool states it explicitly or a non-admin is refused; and core's default for a new page is already hidden, so the read-back's discard path is exercised against TCAdefaults.pages.hidden = 0, the case it exists for. Every surface that counts the tools moves from 46/five to 47/six: README, Tools.rst, the landing-page data and ProductFactsConsistency. Closes #831 Assisted-by: claude-code:claude-fable-5 Agent-Session: https://claude.ai/code/session_0124WZK5UoAM9oYQoSYF1Y8z Agent-Host: 32116e Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
Automated approval for maintainer PR
All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #832 +/- ##
============================================
- Coverage 87.01% 86.74% -0.27%
- Complexity 9809 9865 +56
============================================
Files 572 573 +1
Lines 31733 31920 +187
============================================
+ Hits 27611 27689 +78
- Misses 4122 4231 +109
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
The fourth plan() writer made two more blocks identical across all four: the guard execute() opens with (acting user, backend environment, live workspace) and the DataHandler creation of one record with the read-back of its uid. SonarCloud counted the fourth copy as 4.5 % new duplication against a 3 % gate — and a private copy per file would have relocated it, not removed it. Both move into PlansOneEditorialWriteTrait as writableActingUser() and createRecord(); CreatePageDraftTool, CreateContentElementDraftTool, MoveContentElementTool and CreateTranslationDraftTool use them. What stays per tool is plan() and everything that reads its shape. The two pre-ADR-146 writers are not retrofitted, as ADR-146 decided. ADR-180 records the review ADR-146 asked for at this writer. Also names the repeated test title once (php:S1192). Assisted-by: claude-code:claude-fable-5 Agent-Session: https://claude.ai/code/session_0124WZK5UoAM9oYQoSYF1Y8z Agent-Host: 32116e Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
There was a problem hiding this comment.
Automated approval for maintainer PR
All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.
|
|
Self-review: 4a55542 The review this pull request demands is unsatisfiable (Copilot quota wall or repeated bot failures on this head). Per the documented fallback, the diff on this head was reviewed by the PR author; this comment is the on-the-record attestation the merge gate reads back. It stops matching on the next push. |
Both ADR-180 (#832) and ADR-181 appended to the ADR toctree; the merge keeps both entries in order. Assisted-by: claude-code:claude-fable-5 Agent-Session: https://claude.ai/code/session_0124WZK5UoAM9oYQoSYF1Y8z Agent-Host: 32116e Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>



Closes #831.
What
create_page_draft— the sixth writing tool, and the first that creates a page. It creates ONE standard page under a parent page: always hidden, always in the default language, withtitle,nav_titleand position (parent, optionalafter_page_uidthat must be a subpage of the same parent) as the whole field set; the URL segment is left to the DataHandler's generator. Every other page field (hidden,doktype,slug,fe_group,perms_*, …) is refused by name. It follows the five existing writers to the letter: disabled by default,editinggroup,NON_IDEMPOTENT_WRITE, approval before every call (ADR-134), preview at suspend (ADR-136), DataHandler under the acting user'sPAGE_NEWpermission on the parent, read-after-write with discard of a page that came out visible, and a refusal vocabulary that never confirms a uid. Editor action declared onpageswithparentas the uid-carrying argument (ADR-152).Why this shape — ADR-180
ADR-146 named two revisit triggers: a sixth writer and more than one record per call. Both fired, because the obvious shape was "page plus first element in one call". ADR-180 keeps the one-record rule: the tool creates the page and nothing on it, and its success message hands the model the new uid and names
create_content_element_draftfor the text. Two approvals, each card showing one record. ADR-146 carries the:Amended:field;AdrLifecycleTestchecks both ends.Two things the functional tests taught
recordEditAccessInternals(..., newRecord: true)) readssys_language_uidfrom the incoming record — a non-admin is refused with "languageField … not found in testing record" when it is missing. The tool states it explicitly (it is the default language anyway).hidden = 1, so the exclude-field drop the content-element test relies on changes nothing on stock core. The discard test therefore setsTCAdefaults.pages.hidden = 0on the parent, the installation shape the read-back exists for — and the page that came out visible is deleted again.Surfaces
Tool counts move from 46 / five to 47 / six everywhere
ProductFactsConsistencyTestlooks: README,Tools.rst(new section, group table, counts), the seven landing-page data files, and the pinned number in the test itself. New iconnrllm-editor-action-create-page, XLIFF labels (en/de), CHANGELOG under Unreleased.Gates run locally (one matrix cell, PHP 8.5 / TYPO3 14)
cgl ✓ · phpstan (level 10) ✓ · unit (7263 tests) ✓ · fuzzy ✓ · changelog ✓ · functional
-d sqlite, filtered to the tool, editor-action and effect-coverage classes (63 tests) ✓. Rector did not run locally — this worktree's.Buildis resolved under PHP 8.4 and the pinned-p 8.2dies onplatform_check.php; CI is the place it runs. The full functional suite is left to CI asTests/AGENTS.mdadvises.Assisted by claude-code:claude-fable-5 — Session