Fold demo-build learnings: hosted lying-success API traps + Swift 2.4 authoring recipes#63
Merged
Conversation
… authoring recipes
A hosted-demo polish session surfaced a cluster of surfaces that report `ok` while
writing nothing on ACL-locked installs, plus three Swift 2.4 authoring recipes with no
documented home. Folds them across dw-demo-base, dw-extend-scheduled-tasks, and dw-demo-swift.
Hosted lying-success (dw-demo-base/references/online-mode.md): IndexBuilderSave round-trips
`ok` while the /Files/System/Repositories/** XML write is ACL-denied — assert the
IndexBuilderByName readback, not the status. A Full BuildIndex reads EcomGroupProductRelation
through an app-lifetime cache, so after a relation write the canonical order is recycle-first
then Full build; the rebuild alone no-ops and reads as "API index builds are dead on this host".
And changeversion.txt fires on a CHANGED token, not on presence — re-uploading the current
value is a silent no-op; write a distinct value every time.
Commerce shop reads (foundational/commerce-catalog.md): GetShopById returns a
{id,name,permission} stub — the full model comes only from the namespaced GetShopByIdQuery,
and saving the stub clobbers the omitted fields. ShopSave without an explicit UsageType defaults
ShopType=0 (none), which hides the shop from every typed admin list; pointer added from
dw-demo-pim canonical-setup-order step 2.
RunSqlScheduledTaskAddIn (dw-extend-scheduled-tasks): write-only — no resultset, no message
text, empty lastException even for SELECT 1/0. Read-verify with assertion SQL
(IF <cond> RAISERROR) — the read path when SQL is only reachable through the task addin.
Swift 2.4 authoring: the facet sidebar is a 2-column grid row, not a Layout-field toggle
(foundational/swift-building.md §3); repeater children live in ItemType_*_Item rows via
ItemList/ItemListRelation, unreachable through the Management API, editable only by guarded SQL
plus a recycle (foundational/content-modelling.md §2); conditional-collapse CSS must use flat
sibling :has()/:not(:has()) pairs — nested :has() is invalid and silently dropped — and needs
!important to beat the Swift grid attribute-selector specificity floor (dw-demo-swift/re-skin.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YayhziToTuSR25h6PFxpj2
…op — it recycles on R0-NET, version unchanged Owner correction on fold #63: only a CHANGED token switches the release ring, but a same-value re-upload still recycles the app (observed on an R0-NET ring token) while leaving the version pinned. Rung 3 and the 4.11.5 changelog entry now state both effects: distinct token to switch (confirm via info.version); same-value upload risks an unintended recycle and proves nothing about the ring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YayhziToTuSR25h6PFxpj2
…i/ParagraphSave, not SQL+recycle Corrects the #20 fold in dw-demo-base content-modelling.md §2. The prior claim — repeater children (Swift-v2_Slider slides, accordion items) are "unreachable through the Management API, editable only by guarded SQL plus a recycle" — was wrong. Proven empirically on the Foundry harness host (Swift 2.4 baseline, DW 10.28.1): the admin Visual Editor's slide editor is a SPA client of /Admin/Api, and its save is POST /Admin/Api/ParagraphSave. Captured the UI call and replayed it headlessly (Bearer token, no browser) to CREATE a slide and then EDIT it in place — no SQL, no recycle — and the storefront rendered both changes on the next GET. - Child identity: ContentItem|<Parent>|<Group>|Items[] entries keyed by ItemId (empty = create, existing id = edit in place; verified count-stable update). - Field values ride in the ModelRawData JSON string keyed RelationItem|<ChildType>|<Group>|<Field>; RelationItem.Groups is sent empty. - No recycle: ParagraphSave runs the domain service that invalidates the cache. - Kept the storage-shape truth (ItemType_*_Item via ItemList/ItemListRelation; GetParagraphById collapses to Items=<listId>) — only the edit-path claim was wrong. - ParagraphSave is a lying-success surface for this shape (a malformed child returns ok, creates nothing, and can zero the parent list pointer) — added a round-trip-verify caution. Updates the CHANGELOG [4.11.5] repeater-child bullet accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YayhziToTuSR25h6PFxpj2
…tent motion — API-first Eradicates the "escape to SQL (direct, or via RunSqlScheduledTaskAddIn) when the API gets hard" reflex from the demo skills. The admin UI is a SPA over /Admin/Api: if the UI can do it, an endpoint exists — capture the network call and replay it (MCP -> Management API), and file a learning rather than reaching for SQL. - dw-demo-swift/references/sql-direct-seeding.md: gutted to a deprecation stub pointing at the API-first rule (file kept so inbound links resolve; validator green). - dw-demo-swift/SKILL.md: dropped the "SQL-direct content seeding" trigger and rewrote the routing row to the API-first path (regenerated manifest.json). - dw-demo-base/references/foundational/data-access.md: reframed the "SQL-direct content seeding" section as a forensic/teardown schema reference, not an authoring recipe; softened the save_pages no-op fallback to a targeted local SQL touch-up (creation stays on the API). - dw-extend-scheduled-tasks/SKILL.md: kept the RunSqlScheduledTaskAddIn write-only / assertion-SQL platform truth as a developer diagnostic; added a scope guard that demo/content work must not use it for edits. Scope note: the ERP DB-mock's between-demo RESET fixture task (dw-demo-erp) is a deliberate state-reset, not a content-authoring escape hatch, and is left intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YayhziToTuSR25h6PFxpj2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Folds a hosted-demo polish session's learnings. Version 4.11.5.
Hosted lying-success (
dw-demo-base/references/online-mode.md)IndexBuilderSaveround-tripsstatus: okwhile the/Files/System/Repositories/**XML write is ACL-denied — assert theIndexBuilderByNamereadback, not theok. Added to the hosted failure-mode list with a mandatory read-after-write on repository-config saves.BuildIndexreadsEcomGroupProductRelationthrough an app-lifetime cache — after a relation write the canonical order is recycle-first, then Full build; the rebuild alone no-ops and reads as "API index builds are dead on this host".changeversion.txtfires on a CHANGED token, not on presence (restart ladder rung 3) — re-uploading the current value is a silent no-op; write a distinct value every time.Commerce shop reads (
foundational/commerce-catalog.md)GetShopByIdreturns a{id,name,permission}stub — the full model comes only from the namespacedGetShopByIdQuery; saving the stub clobbers the omitted fields.ShopSavewithout an explicitUsageTypedefaultsShopType=0(none), hiding the shop from every typed admin list. Pointer added fromdw-demo-pimcanonical-setup-order step 2.Scheduled tasks (
dw-extend-scheduled-tasks/SKILL.md)RunSqlScheduledTaskAddInis write-only — no resultset, no message text, emptylastExceptioneven forSELECT 1/0. Read-verify with assertion SQL (IF <cond> RAISERROR).Swift 2.4 authoring
Layout-field toggle (foundational/swift-building.md§3).ItemType_*_Itemrows viaItemList/ItemListRelation(storage-shape truth retained), and are created + edited throughPOST /Admin/Api/ParagraphSave— see the Correction section below (foundational/content-modelling.md§2).:has()/:not(:has())pairs — nested:has()is invalid and silently dropped — and needs!importantto beat the Swift grid attribute-selector specificity floor (dw-demo-swift/re-skin.md).Validator:
python3 scripts/validate-skills.py→ 0 errors, 0 warnings. Sanitize grep packs (names/hosts/keys, session-time, customer paths) clean across the staged diff and the commit message.Correction — #20 repeater-child edit path (empirically re-proven)
The original "Repeater children … unreachable through the Management API — editable only by guarded SQL plus a recycle" claim (Foundry issue #20) was wrong and has been corrected.
Proven end-to-end on the Foundry harness host (Swift 2.4 baseline restored, DW 10.28.1): the admin Visual Editor's slide editor is a SPA client of
/Admin/Api. Captured its save call and replayed it headlessly (Bearer token, no browser) to CREATE aSwift-v2_Sliderchild slide and then EDIT it in place — no SQL, no recycle — and the storefront rendered both changes on the next GET.Proven recipe —
POST /Admin/Api/ParagraphSave?Query.Type=GetParagraphById(Bearer):ContentItem|Swift-v2_Slider|General|Items[]carries child entries.ItemId:""creates, an existing id (e.g."1") edits in place (verified count-stable).ModelRawDataJSON string keyedRelationItem|Swift-v2_Slider_Item|General|<Field>;RelationItem.Groupsis sent empty.ParagraphSaveis a lying-success surface for this shape (a malformed child returnsok, creates nothing, and can zero the parent list pointer) → round-trip-verify.Doctrine change — retire the SQL-via-scheduled-task / SQL-direct content motion
Eradicated the "escape to SQL (direct, or via
RunSqlScheduledTaskAddIn) when the API gets hard" reflex from the demo corpus. The admin UI is API-first — capture the UI's/Admin/Apicall and replay it (MCP → Management API); file a learning rather than reaching for SQL.dw-demo-swift/references/sql-direct-seeding.md→ deprecation stub (file kept; validator green).dw-demo-swift/SKILL.md→ dropped the "SQL-direct content seeding" trigger; routing rewritten (manifest regenerated).foundational/data-access.md"SQL-direct content seeding" → reframed as forensic/teardown reference, not an authoring recipe.dw-extend-scheduled-tasks/SKILL.md→ kept theRunSqlwrite-only / assertion-SQL platform truth as a developer diagnostic; added a guard that demo/content editing must not use it.dw-demo-erp) is a deliberate state-reset, not a content-authoring escape hatch — left intact.Commits:
1d6778a(Phase B, #20 fix) ·cc1b147(Phase C, doctrine sweep).