@praxisui/dynamic-form 9.0.67 → 9.0.68-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -0
- package/ai/component-registry.json +12 -12
- package/docs/actions-optional-text-validation-2026-09-08.md +49 -0
- package/docs/dynamic-form-authoring-document-semantics.md +87 -0
- package/docs/entity-read-feedback.md +162 -0
- package/docs/layout-apply-save-reopen-2026-09-08.md +114 -0
- package/docs/layout-toolbar-accessibility-2026-09-08.md +57 -0
- package/docs/master-detail-customization-matrix-2026-09-08.md +182 -0
- package/docs/schema-loading-recovery.md +74 -0
- package/docs/section-spacing-authoring-2026-09-08.md +61 -0
- package/fesm2022/praxisui-dynamic-form.mjs +3617 -2331
- package/package.json +8 -8
- package/src/lib/config-editor/praxis-dynamic-form-config-editor.json-api.md +11 -0
- package/src/lib/layout-editor/praxis-layout-editor.json-api.md +8 -4
- package/src/lib/praxis-dynamic-form.json-api.md +11 -0
- package/types/praxisui-dynamic-form.d.ts +116 -7
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Feedback local na troca de registro
|
|
2
|
+
|
|
3
|
+
Estado consolidado em 08/09/2026: feedback local, erro/retry, recuperação de foco
|
|
4
|
+
e ocultação sem transição implementados e validados. As seções de evidência abaixo
|
|
5
|
+
são cronológicas; contagens, limitações e ausência de gravação pertencem à etapa
|
|
6
|
+
descrita, não substituem resultados posteriores. A configuração da página real foi
|
|
7
|
+
aplicada na etapa de [apresentação do cabeçalho](../../praxis-core/docs/widget-header-presentation-followup.md).
|
|
8
|
+
Consulte a [revisão final de documentação e skills](../../praxis-core/docs/widget-identity-documentation-review.md)
|
|
9
|
+
para o estado das orientações canônicas e seus limites de validação.
|
|
10
|
+
|
|
11
|
+
## Escopo e inventário
|
|
12
|
+
|
|
13
|
+
Mudança transversal pelo consumo do Dynamic Form em páginas, widgets e diálogos,
|
|
14
|
+
sem novos inputs, outputs, opções de editor ou contratos HTTP. Fonte canônica:
|
|
15
|
+
`PraxisDynamicForm.loadEntity`; consumidores continuam usando `resourceId`.
|
|
16
|
+
|
|
17
|
+
A pendência de hidratação, os eventos `loadingStateChange` e o cancelamento da
|
|
18
|
+
leitura já existiam. Aderência: `ja-suportado-mal-nomeado-ou-mal-materializado`
|
|
19
|
+
para feedback; `suportado-parcialmente` para falha e recuperação.
|
|
20
|
+
|
|
21
|
+
## Comportamento
|
|
22
|
+
|
|
23
|
+
- Durante a leitura, o corpo mantém geometria e componentes montados, mas fica
|
|
24
|
+
totalmente transparente, `inert` e `aria-hidden`. O status local fica fora da
|
|
25
|
+
região marcada `aria-busy`, permitindo anunciar o carregamento.
|
|
26
|
+
- Não usar apenas `visibility:hidden`: campos podem definir `visibility:visible`
|
|
27
|
+
e reaparecer. Essa situação foi detectada e corrigida no navegador real.
|
|
28
|
+
- Erros e respostas inválidas mantêm o corpo e o envio bloqueados. A ação local
|
|
29
|
+
de nova tentativa invalida a deduplicação e lê novamente a identidade atual.
|
|
30
|
+
- O sucesso substitui o snapshot com `form.reset(normalized)`, limpando valores
|
|
31
|
+
ausentes em vez de carregar campos da pessoa anterior. Leituras substituídas
|
|
32
|
+
continuam canceladas; alteração de identidade durante hooks cancela o envio.
|
|
33
|
+
- Criação e snapshots locais authorados por `initialValue` preservam seu fluxo.
|
|
34
|
+
|
|
35
|
+
## Validação
|
|
36
|
+
|
|
37
|
+
A bateria focal de seleção, runtime/submit, external-config-hydration e
|
|
38
|
+
first-config-hydration passou com 238 testes. Build oficial focal:
|
|
39
|
+
`npm run build:praxis-dynamic-form`, sucesso. Logs locais:
|
|
40
|
+
`/tmp/praxis-entity-read-tests-final.log` e `/tmp/praxis-entity-read-build.log`.
|
|
41
|
+
Após separar o status da região `aria-busy`, os 11 testes de seleção foram
|
|
42
|
+
reexecutados e passaram (`/tmp/praxis-entity-read-a11y-final.log`). Essa execução
|
|
43
|
+
recompilou o template final; o build de pacote precedeu esse último ajuste ARIA.
|
|
44
|
+
|
|
45
|
+
Foram acrescentados testes para ocultação sem desmontar, erro e retry pelo botão,
|
|
46
|
+
bloqueio de submit após erro, resposta parcial, resposta inválida, B tardio após C
|
|
47
|
+
e troca de identidade durante hooks. Os casos existentes cobrem limpar seleção,
|
|
48
|
+
cancelamento e preservação de criação/initialValue. Dois fixtures visuais
|
|
49
|
+
inicialmente falharam por inicialização incompleta; foram corrigidos antes da
|
|
50
|
+
bateria final.
|
|
51
|
+
|
|
52
|
+
CUA em `localhost:4003/page-builder-ia`, sem interceptação de rede: troca real
|
|
53
|
+
entre funcionários, cabeçalho imediato, corpo anterior oculto, status local e
|
|
54
|
+
conteúdo atualizado após sucesso. Conferidos desktop escuro e 390×844 em tema
|
|
55
|
+
claro; árvore de acessibilidade durante loading sem os campos anteriores. Tema,
|
|
56
|
+
viewport e modo de edição restaurados. Nenhum registro ou página remota foi salvo.
|
|
57
|
+
Falha/retry foi validada por teste de componente, sem provocar erro no backend
|
|
58
|
+
real. Não foi realizada sessão com leitor de tela nem publicação de pacotes.
|
|
59
|
+
|
|
60
|
+
## Artefatos derivados
|
|
61
|
+
|
|
62
|
+
README atualizado. Não houve alteração de public-api, shapes de configuração,
|
|
63
|
+
operações de authoring ou portas: não há novo campo didático no editor nem novo
|
|
64
|
+
link a apresentar. Manifestos AI, registry e corpus HTTP não exigem regeneração.
|
|
65
|
+
Naquela etapa, o guidance instalado de runtime mencionava apenas bloqueio durante pending; a
|
|
66
|
+
família correspondente não está disponível em `codex-skills/` deste checkout
|
|
67
|
+
do monorepo. A sincronização dessa orientação ficou registrada, sem editar só
|
|
68
|
+
a cópia instalada nem criar outra skill paralela. A revisão final localizou a
|
|
69
|
+
fonte em `praxis-codex-skills` e resolveu essa lacuna na skill existente de runtime.
|
|
70
|
+
|
|
71
|
+
## Prova visual adicional de falha e recuperação
|
|
72
|
+
|
|
73
|
+
O laboratório `/dynamic-page-lab` agora inclui o painel “Validação técnica:
|
|
74
|
+
atualização e recuperação do formulário”. O componente
|
|
75
|
+
`src/app/features/dynamic-page-lab/form-entity-read-proof.component.ts` usa
|
|
76
|
+
`PraxisDynamicForm` e `WidgetShellComponent` reais, com um `HttpBackend` controlado
|
|
77
|
+
e restrito à instância da prova. Não envia HTTP nem modifica registros/configuração.
|
|
78
|
+
Os controles de demonstração completam ou falham a leitura explicitamente;
|
|
79
|
+
não há timers que tornem a inspeção visual dependente da velocidade do operador.
|
|
80
|
+
|
|
81
|
+
Validação via CUA:
|
|
82
|
+
|
|
83
|
+
- Ana carregada → Bruno pendente → falha: cabeçalho Bruno, mensagem local e
|
|
84
|
+
botão de nova tentativa; valores anteriores ausentes da árvore acessível.
|
|
85
|
+
- Enter em “Tentar novamente”: contagem de leituras 2 → 3; após concluir, nome e
|
|
86
|
+
contato são de Bruno. O transporte real da API não foi exercitado neste cenário.
|
|
87
|
+
- Erro em 390×844, tema escuro: mensagem quebra em duas linhas, botão visível,
|
|
88
|
+
sem sobreposição; Tab alcança o elemento seguinte.
|
|
89
|
+
- Bruno → Ana → limpar durante pendência: leitura cancelada, nenhum pedido
|
|
90
|
+
pendente e estado de seleção vazia visível. Foco permaneceu em “Limpar seleção”.
|
|
91
|
+
- O servidor Angular recompilou a demonstração. Não foi reexecutada a bateria
|
|
92
|
+
de runtime nem o build de pacote, pois esta etapa só adicionou o consumidor de
|
|
93
|
+
laboratório e documentação. `resourceId` vazio usa `undefined`, conforme o
|
|
94
|
+
tipo público atual; o runtime normaliza essa ausência para seleção vazia.
|
|
95
|
+
|
|
96
|
+
### Pendência encontrada: foco após retry
|
|
97
|
+
|
|
98
|
+
Ao acionar “Tentar novamente” por Enter, o botão é removido durante o loading e
|
|
99
|
+
o foco retorna ao documento. A recuperação de dados funciona, mas essa transição
|
|
100
|
+
de foco ainda precisa ser corrigida no Dynamic Form e coberta por teste. O
|
|
101
|
+
critério recomendado é manter orientação dentro do detalhe quando a nova
|
|
102
|
+
tentativa foi explicitamente acionada, sem roubar o foco de quem mudou a seleção
|
|
103
|
+
ou navegou para outro controle durante a leitura. Esta prova não equivale a uma
|
|
104
|
+
certificação completa com leitor de tela.
|
|
105
|
+
|
|
106
|
+
### Correção e validação do foco
|
|
107
|
+
|
|
108
|
+
A pendência acima foi corrigida no Dynamic Form. A região estável “Dados do
|
|
109
|
+
registro”, com `tabindex=-1`, recebe foco somente na nova tentativa explicitamente
|
|
110
|
+
acionada. Permanece montada no carregamento, erro e sucesso. A resposta não chama
|
|
111
|
+
focus, portanto não retira o foco de quem navegou para outro controle. Uma região
|
|
112
|
+
live persistente anuncia carregamento, erro e sucesso; o texto visual duplicado
|
|
113
|
+
fica fora da árvore acessível. Strings disponíveis em português e inglês.
|
|
114
|
+
|
|
115
|
+
A bateria de runtime/submit/hidratação passou com **240 testes**. Depois do ajuste
|
|
116
|
+
final para evitar texto duplicado, os **13 testes de seleção** foram reexecutados
|
|
117
|
+
e passaram, assim como o build final do pacote. Logs:
|
|
118
|
+
`/tmp/praxis-retry-focus-tests.log`, `/tmp/praxis-retry-focus-final.log` e
|
|
119
|
+
`/tmp/praxis-retry-focus-build-final.log`.
|
|
120
|
+
|
|
121
|
+
CUA confirmou Enter em retry com foco na região de dados no desktop e em 390×844;
|
|
122
|
+
após concluir a leitura, a árvore acessível contém “Dados atualizados” e os valores
|
|
123
|
+
atuais. Preservação do foco até a resposta e não interferência após navegação para
|
|
124
|
+
outro controle foram verificadas com DOM real nos testes de componente. Não houve
|
|
125
|
+
sessão com leitor de tela. Nenhuma configuração remota foi gravada.
|
|
126
|
+
|
|
127
|
+
## Inventário histórico da evolução de apresentação e integração
|
|
128
|
+
|
|
129
|
+
Inventário inicial, sem novo contrato criado nessa etapa. Vazio, subtítulo
|
|
130
|
+
condicional, formatação e ações estreitas foram posteriormente tratados conforme
|
|
131
|
+
o relatório de apresentação do cabeçalho vinculado acima; a tabela registra a
|
|
132
|
+
decisão anterior à implementação, não pendências atuais.
|
|
133
|
+
|
|
134
|
+
| Necessidade | Aderência e fonte existente | Trabalho restante |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| Detalhe sem seleção | Já suportado pelo `emptyState` do formulário | Compor a mensagem adequada da página |
|
|
137
|
+
| Cabeçalho vazio mostrando separador | Suportado parcialmente: interpolação de caminhos em Core, sem composição condicional do subtítulo | Auditar materializações/transformações canônicas antes de propor fallback público |
|
|
138
|
+
| Nascimento/CPF no cabeçalho | Suportado parcialmente: `ValuePresentationConfig`/resolver de Core e máscaras de exibição de Dynamic Fields; shell recebe texto | Definir como a apresentação governada chega ao título/subtítulo sem acoplar o shell a funcionário |
|
|
139
|
+
| Ações em largura estreita | Já suportado, mal materializado: shell possui grupos de ações e quebra de linha | Projetar prioridade/overflow no owner Core e conferir editor aberto |
|
|
140
|
+
|
|
141
|
+
Mapa de impacto da próxima evolução: Core (shell/composição), Page Builder
|
|
142
|
+
(editor/capabilities caso haja opção nova), Dynamic Fields (reuso de apresentação),
|
|
143
|
+
consumidor oficial e documentação pública. Qualquer mudança no shape do shell
|
|
144
|
+
exige plano de contrato público, testes de round-trip e revisão de manifestos e
|
|
145
|
+
playgrounds antes da implementação. O inventário acima não declara ainda uma
|
|
146
|
+
lacuna real de contrato.
|
|
147
|
+
|
|
148
|
+
Para integrar esta correção, revisar em conjunto o runtime/template/SCSS/i18n e
|
|
149
|
+
spec de seleção de Dynamic Form, seu README e este documento, mais o componente
|
|
150
|
+
de prova e sua inclusão no Dynamic Page Lab. O checkout contém alterações de
|
|
151
|
+
outras tarefas, inclusive nos mesmos arquivos; não incluir o diretório inteiro
|
|
152
|
+
automaticamente em commit/PR. Nenhum commit, push ou publicação foi executado.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## Ocultação sem transição entre identidades
|
|
156
|
+
|
|
157
|
+
Durante leitura pendente ou falha, o elemento `form` também recebe `transition:
|
|
158
|
+
none`. A opacidade zero deve ser efetiva no primeiro frame: animações de saída
|
|
159
|
+
não podem manter o registro anterior parcialmente visível sob o novo cabeçalho.
|
|
160
|
+
Ao concluir, o override transitório é removido. `inert`, `aria-hidden` e a reserva
|
|
161
|
+
de espaço continuam ativos durante a espera. A regra pertence ao Dynamic Form,
|
|
162
|
+
não à página consumidora, e não acrescenta configuração pública ou texto novo.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Form layout: Apply, Save and reopen
|
|
2
|
+
|
|
3
|
+
## Scope and isolation
|
|
4
|
+
|
|
5
|
+
Classification: `docs-apenas` for the repository changes. The operational proof
|
|
6
|
+
reused `/remote-config-storage-persistence-lab` without changing production code,
|
|
7
|
+
routes, providers or contracts. Existing editor documents, configuration storage
|
|
8
|
+
and widget identities already support the journey; no new contract was required.
|
|
9
|
+
|
|
10
|
+
The original `/page-builder-ia` document remained at version 92. Its payload was
|
|
11
|
+
copied through the reference Config API into the existing lab's session identity,
|
|
12
|
+
after a GET confirmed that the target did not exist (404):
|
|
13
|
+
|
|
14
|
+
- Component type: `praxis-dynamic-page`.
|
|
15
|
+
- Component ID: `dynamic-page:remote-canvas-resize-proof:ik=bf5a3dd8-27c8-4aed-b367-afffd680794f`.
|
|
16
|
+
- Lab tenant/user: `demo` / `codex-remote-persistence-lab`, environment `local`.
|
|
17
|
+
- UI tab: 15, opened on the existing remote persistence lab.
|
|
18
|
+
|
|
19
|
+
Every widget key and matching composition/canvas reference was remapped. Form ID,
|
|
20
|
+
table ID and component-instance IDs also received the run UUID. The original
|
|
21
|
+
resource paths, layouts and modes were retained. The setup PUT created version 1;
|
|
22
|
+
it was fixture preparation, not an action performed in the visual editor. All
|
|
23
|
+
subsequent layout edits and saves used the actual UI. This proves the embedded
|
|
24
|
+
Form + DynamicWidgetPage + ApiConfigStorage path, not the complete Page Builder
|
|
25
|
+
host/agentic-document path used by `/page-builder-ia`.
|
|
26
|
+
|
|
27
|
+
## Observed journey
|
|
28
|
+
|
|
29
|
+
1. Reloaded the lab and opened its proof. Status became **restaurada**. Selected
|
|
30
|
+
Ayla, opened **Configurar formulário → Layout**.
|
|
31
|
+
2. Moved Nome Completo right of CPF using the column menu and clicked **Aplicar**.
|
|
32
|
+
The displayed detail changed and the page host reported unsaved changes.
|
|
33
|
+
3. Moved Nome Completo left again, then cancelled and confirmed **Descartar
|
|
34
|
+
rascunho**. The already-applied CPF → Nome Completo order remained visible and
|
|
35
|
+
was reconstructed when reopening Layout. This exercises opening A → draft B
|
|
36
|
+
→ Apply B → draft A → discard A, without treating Apply as a remote save.
|
|
37
|
+
4. Read the copy through the API: it still exactly matched seeded version 1.
|
|
38
|
+
5. Moved Email after Telefone in Contato and used **Salvar e fechar** in the Form
|
|
39
|
+
editor. Then used **Salvar layout de teste** in the page host. Status became
|
|
40
|
+
**salva** after the host saved and read back its document.
|
|
41
|
+
6. A separate GET returned version 2 with a changed ETag. The persisted layout
|
|
42
|
+
contained CPF → Nome Completo and Telefone → Email. The contact-column widths
|
|
43
|
+
travelled with their columns (Telefone 4/12, Email 8/12). Mode remained `view`,
|
|
44
|
+
presentation remained `true`, all five composition links matched the seed,
|
|
45
|
+
and page state remained `{ "values": {} }`.
|
|
46
|
+
7. Reloaded the browser and reopened the proof. After loading completed, status
|
|
47
|
+
was **restaurada** and the empty-selection instruction appeared. Keyboard
|
|
48
|
+
selection subsequently loaded Ayla. Both edited orders were present in the
|
|
49
|
+
rendered detail and in the reopened Layout editor. A stabilized General tab
|
|
50
|
+
showed **Visualizar** and **Apresentação** checked.
|
|
51
|
+
|
|
52
|
+
Final GETs confirmed that the original was unchanged at version 92 and the copy
|
|
53
|
+
was unchanged at version 2 after reload and selection. No employee write command
|
|
54
|
+
was executed. The copy is retained under the owned identity above for review and
|
|
55
|
+
the selection investigation; it is not a published preset.
|
|
56
|
+
|
|
57
|
+
## Separate selection observation
|
|
58
|
+
|
|
59
|
+
Do not certify the entire interaction flow as defect-free. After reload, pointer
|
|
60
|
+
actions on the selection radio sometimes produced a visually checked radio while
|
|
61
|
+
the table's selection announcement/action availability and detail remained empty.
|
|
62
|
+
A later snapshot showed radio 194 checked while the status still described record
|
|
63
|
+
193 deselected with zero selections. A click on the Sol row's text also did not
|
|
64
|
+
replace Ayla's detail. Pressing Space on radio 193 did publish selection and load
|
|
65
|
+
the detail correctly.
|
|
66
|
+
|
|
67
|
+
The saved configuration still enables row-click selection and all five links are
|
|
68
|
+
unchanged. Therefore loss of the persisted link is not supported by the evidence.
|
|
69
|
+
The lab holds page customization enabled; pointer interception, radio native
|
|
70
|
+
activation versus Table selection, and interaction timing remain candidates to
|
|
71
|
+
distinguish. No runtime root cause is established, and no speculative patch was
|
|
72
|
+
made. A transient selector deadline while loading the empty state was followed by
|
|
73
|
+
a snapshot proving that the state was present; it is not evidence of a lost
|
|
74
|
+
empty-state setting. Initial immediate mode snapshots also preceded panel
|
|
75
|
+
rendering; the stabilized General tab confirmed both modes.
|
|
76
|
+
|
|
77
|
+
Follow-up: the radio inconsistency was subsequently reproduced in standalone
|
|
78
|
+
Table DOM tests and corrected at its Material `change` handler. The retained
|
|
79
|
+
copy passed pointer selection, switching records, repeated activation, Space
|
|
80
|
+
clear and row-cell selection; see the
|
|
81
|
+
[radio selection evidence](../../praxis-table/test-dev/radio-pointer-selection-2026-09-08.md).
|
|
82
|
+
This establishes the reproduced radio cause without attributing earlier browser
|
|
83
|
+
crashes to it.
|
|
84
|
+
|
|
85
|
+
The follow-up also found an error in this run's fixture preparation: it had added
|
|
86
|
+
`componentInstanceId` to Rich Content, which does not declare that input. On a
|
|
87
|
+
fresh dev load, metadata validation rejected it. A separate If-Match-protected
|
|
88
|
+
fixture correction removed only this input and advanced the copy to version 3;
|
|
89
|
+
all saved layouts, links and Table/Form identities were preserved. Version 2 is
|
|
90
|
+
the historical UI-save receipt above; version 3 is the corrected retained copy.
|
|
91
|
+
The original page remained unchanged at version 92.
|
|
92
|
+
|
|
93
|
+
## Evidence and validation limits
|
|
94
|
+
|
|
95
|
+
Read-only receipts/snapshots from this run:
|
|
96
|
+
|
|
97
|
+
- `/tmp/praxis-layout-roundtrip-owned.json`: ownership, initial status and ETag.
|
|
98
|
+
- `/tmp/praxis-layout-roundtrip-seed.json`: version 1.
|
|
99
|
+
- `/tmp/praxis-layout-roundtrip-after-apply.json`: still identical to version 1.
|
|
100
|
+
- `/tmp/praxis-layout-roundtrip-saved.json`: version 2 with both column moves.
|
|
101
|
+
- `/tmp/praxis-layout-roundtrip-reloaded.json`: unchanged version 2.
|
|
102
|
+
- `/tmp/praxis-layout-roundtrip-original-after.json`: unchanged original version 92.
|
|
103
|
+
|
|
104
|
+
Runtime/editor assertions were based on rendered DOM, actual UI actions and
|
|
105
|
+
independent API reads. They do not establish which individual child storage
|
|
106
|
+
requests carried If-Match, enumerate all child config keys, or prove conflict
|
|
107
|
+
handling against deliberately older child preferences. The page version/ETag
|
|
108
|
+
change is confirmed; request-header conformance was not captured in this run.
|
|
109
|
+
|
|
110
|
+
No unit suite or production build was rerun for documentation-only changes. No
|
|
111
|
+
public API, generated manifest, public example, HTTP corpus or skill needed an
|
|
112
|
+
update: `praxis-form-editor-document-roundtrip` already distinguishes Apply,
|
|
113
|
+
component Save, page Save and rehydration. The finding adds concrete evidence,
|
|
114
|
+
not new platform guidance.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Layout toolbar: accessible editor preferences
|
|
2
|
+
|
|
3
|
+
Classification: `local-pequena`. Adherence:
|
|
4
|
+
`ja-suportado-mal-nomeado-ou-mal-materializado`. Dynamic Form already owns density
|
|
5
|
+
and border/separator editor state, Material toggles, CSS token bindings and an
|
|
6
|
+
i18n namespace. No missing contract justified a new input, configuration flag,
|
|
7
|
+
token or persisted setting.
|
|
8
|
+
|
|
9
|
+
The three density controls and two style controls previously had hardcoded
|
|
10
|
+
Portuguese tooltips but no accessible names on their native buttons. The style
|
|
11
|
+
group was also unnamed. The group labels did not distinguish editor preferences
|
|
12
|
+
from changes to the published form.
|
|
13
|
+
|
|
14
|
+
The fix adds translated accessible names to the Material inputs (not only their
|
|
15
|
+
hosts), translates both group labels and the toolbar name, and explains the
|
|
16
|
+
editor-only scope in tooltips. Visible groups are now **Densidade do editor** and
|
|
17
|
+
**Guias do editor**. `compact/cozy/regular` and `border/divider` retain their
|
|
18
|
+
existing state semantics. No CSS, icon source, token or document shape changed.
|
|
19
|
+
|
|
20
|
+
## Validation
|
|
21
|
+
|
|
22
|
+
- 38 tests passed across `layout-editor-toolbar.spec.ts` and
|
|
23
|
+
`layout-editor.component.spec.ts`. The new cases check native control names in
|
|
24
|
+
pt-BR/en-US, host translator override, selected/pressed states, and preference
|
|
25
|
+
changes without document mutation or configChange emission.
|
|
26
|
+
- The first test compile exposed a fixture translator return-type error; this
|
|
27
|
+
was corrected to use the existing typed host translator contract. Subsequent
|
|
28
|
+
initial-state assertions required a change-detection pass after asynchronous
|
|
29
|
+
ngModel stabilization. The final 38-test run passed.
|
|
30
|
+
- Browser on the official `/page-builder-ia` route, existing tab 8: opened the
|
|
31
|
+
selected employee's Form editor and Layout; verified all five accessible names;
|
|
32
|
+
used Space on Compacta, Bordas das seções and Separadores. States changed while
|
|
33
|
+
**Sem alterações**, disabled Apply and disabled Save remained intact. Restored
|
|
34
|
+
the initial preferences through the same UI.
|
|
35
|
+
- Screenshot review at viewport 1125×912, dark theme, expanded panel and reduced
|
|
36
|
+
panel (720px wide): group labels and controls wrap without overlap; the tooltip
|
|
37
|
+
explains editor-only behavior. This is reduced-panel coverage, not mobile or
|
|
38
|
+
full screen-reader certification. No light-theme screenshot or full AXE audit
|
|
39
|
+
was performed for this naming-only change.
|
|
40
|
+
|
|
41
|
+
Test log: `/tmp/praxis-layout-toolbar-tests-final.log`.
|
|
42
|
+
Build log: `/tmp/praxis-layout-toolbar-build.log`.
|
|
43
|
+
`npm run build:praxis-dynamic-form` completed successfully through the official
|
|
44
|
+
script's dependency/build closure. A final Config API GET confirmed page version
|
|
45
|
+
92, payload and ETag unchanged; receipt:
|
|
46
|
+
`/tmp/praxis-layout-toolbar-config-after.json`. No page or employee save was used.
|
|
47
|
+
|
|
48
|
+
The README now explains these existing preferences. Authoring manifests and
|
|
49
|
+
public APIs need no change: no authorable path, payload or operation changed.
|
|
50
|
+
Public-site examples, HTTP corpus and generated catalogs do not expose a new
|
|
51
|
+
contract to synchronize. Existing layout/design skills already require named
|
|
52
|
+
icon controls, i18n, host overrides and preservation of drafts; no skill change
|
|
53
|
+
or installation sync is needed for this correction.
|
|
54
|
+
|
|
55
|
+
Other hardcoded copy, the global gap control and broader layout composition
|
|
56
|
+
remain outside this focused fix. This does not certify the whole editor as
|
|
57
|
+
localized or redesign its information architecture.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Master-detail customization: controlled comparison
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
Classification: `local-pequena` tests and documentation. Existing widget inputs,
|
|
6
|
+
composition links, authoring document and capabilities represent every scenario;
|
|
7
|
+
no new contract or runtime patch is justified by these results.
|
|
8
|
+
|
|
9
|
+
The reported failure remains open on `/page-builder-ia`. This matrix progressively
|
|
10
|
+
adds factors from that page to the previously passing minimal composition, using
|
|
11
|
+
real Table, Form, widget loader and Page Builder components with controlled HTTP.
|
|
12
|
+
|
|
13
|
+
## Final result
|
|
14
|
+
|
|
15
|
+
All **8 scenarios passed** in ChromeHeadless:
|
|
16
|
+
|
|
17
|
+
| Scenario | Added factor | Result |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| 1 | Direct composition runtime with child customization | Pass |
|
|
20
|
+
| 2 | Page Builder host | Pass |
|
|
21
|
+
| 3 | Saved form layout and metadata: 18 fields, 4 sections | Pass |
|
|
22
|
+
| 4 | Builder agentic control enabled | Pass |
|
|
23
|
+
| 5 | Form AI control also enabled | Pass |
|
|
24
|
+
| 6 | Authoring document plus host `pageChange` acknowledgement | Pass |
|
|
25
|
+
| 7 | Saved identity links, transient state, detail shell and canvas | Pass |
|
|
26
|
+
| 8 | Resource schema discovery/reconciliation with `input-first` layout | Pass |
|
|
27
|
+
|
|
28
|
+
Each scenario uses two fictional employees with populated names, dates, monetary
|
|
29
|
+
values, booleans and job/department references. It clicks real table rows and
|
|
30
|
+
checks both child customization inputs, the selected entity, displayed name,
|
|
31
|
+
view/presentation mode, stable loaded component instances during mode changes,
|
|
32
|
+
unchanged authored page JSON and no page/FormConfig saves. It also leaves editing
|
|
33
|
+
while the second entity read is pending and hovers/selects a form section before
|
|
34
|
+
leaving editing. Section selection is cleared on exit.
|
|
35
|
+
|
|
36
|
+
The reference fields issue canonical `jobRole` and `department` option-source
|
|
37
|
+
`options/by-ids` GETs. The test answers these with matching IDs/labels, ignores
|
|
38
|
+
already-cancelled requests and requires settling within a bounded number of
|
|
39
|
+
response rounds. Earlier name-only responses did not exercise these lookups and
|
|
40
|
+
were insufficient to represent a populated employee detail.
|
|
41
|
+
|
|
42
|
+
Log: `/tmp/praxis-master-detail-schema-boundary.log`. The final eight scenarios
|
|
43
|
+
completed successfully (1.906 seconds of test execution). No full
|
|
44
|
+
workspace suite, production build or live LLM request was run. Enabling AI
|
|
45
|
+
controls does not certify backend AI authoring or session transport.
|
|
46
|
+
|
|
47
|
+
## Fixture provenance and limits
|
|
48
|
+
|
|
49
|
+
`src/lib/test-fixtures/page-builder-employee-form.config.json` takes layout,
|
|
50
|
+
field metadata and editorial block configuration from the version-92 reference
|
|
51
|
+
document. It excludes schema hash/context/verification timestamp and records.
|
|
52
|
+
`page-builder-employee-framing.json` takes its state, five composition links,
|
|
53
|
+
canvas/layout and detail shell; widget keys are mapped to the fixture's `people`
|
|
54
|
+
and `detail`, and the unrelated page-header widget is excluded.
|
|
55
|
+
|
|
56
|
+
These fixtures are test inputs, not new public presets or a second metadata
|
|
57
|
+
source. They intentionally retain field configuration details that a simplified
|
|
58
|
+
handwritten form would omit. Responses are fictional; avatars remain null.
|
|
59
|
+
|
|
60
|
+
`page-builder-employee-response.schema.json` is the response read on September 8
|
|
61
|
+
from the reference API's `/schemas/filtered` for
|
|
62
|
+
`path=/api/human-resources/funcionarios/all&operation=get&schemaType=response`.
|
|
63
|
+
It contains schema metadata and documentation examples, not queried employee
|
|
64
|
+
records. Scenario 8 uses the real SchemaMetadataClient and normalizer, with only
|
|
65
|
+
the `fetch` transport intercepted. Responses use a synthetic ETag and return 304
|
|
66
|
+
when that tag is supplied. The test asserts successful initialization, retained
|
|
67
|
+
authored section IDs, the schema hash, no false outdated warning, and no further
|
|
68
|
+
schema reads during three additional settling turns after the interactions.
|
|
69
|
+
|
|
70
|
+
Initial failures in this extension concerned overly broad persistence assertions,
|
|
71
|
+
not hydration or a reproduced browser crash. The runtime separately persists
|
|
72
|
+
`form-schema-meta:*` evidence/index and `conn:form:*` connection identity with
|
|
73
|
+
`origin: input`. The final assertion checks those keys and payload shapes while
|
|
74
|
+
rejecting page/FormConfig saves. `input-first` and page `autoPersist=false` do not
|
|
75
|
+
mean that every child storage write is disabled. This is observed existing
|
|
76
|
+
behavior, not a new persistence contract. Storage reads still return null in this
|
|
77
|
+
fixture; persisted-child conflict/roundtrip behavior is outside this proof.
|
|
78
|
+
|
|
79
|
+
This matrix does **not** reproduce the full saved-page host: real network timing,
|
|
80
|
+
persisted child configuration loading, the remote table, the app's
|
|
81
|
+
global providers/interceptors/theme, and actual pointer movement
|
|
82
|
+
remain differences. Mouse events in a DOM test cover handlers, not full browser
|
|
83
|
+
hit testing. No factor can be excluded as a cause under every combination merely
|
|
84
|
+
because the controlled scenario passes.
|
|
85
|
+
|
|
86
|
+
## Earlier browser failure
|
|
87
|
+
|
|
88
|
+
The previously responsive reference tab navigated to `/page-builder-ia` and
|
|
89
|
+
loaded its table. Selecting Ayla and waiting for her name in the detail region
|
|
90
|
+
completed; the next request to access the app switch for keyboard interaction
|
|
91
|
+
timed out in `Runtime.evaluate`. The switch transition was not confirmed. This
|
|
92
|
+
does not establish editing as the exclusive trigger: failure may occur after
|
|
93
|
+
detail hydration, before the next interaction can be performed.
|
|
94
|
+
|
|
95
|
+
Old crashed tabs could not be cleaned up through the browser tool: attempting to
|
|
96
|
+
obtain a crashed tab was blocked by its URL policy for the generated crash page.
|
|
97
|
+
No bypass was attempted and clean browser-process recovery is not claimed.
|
|
98
|
+
|
|
99
|
+
Read-only GET after the comparison returned version 92, structurally identical
|
|
100
|
+
to `/tmp/praxis-draft-rollout-final.json`. The saved page was not modified.
|
|
101
|
+
|
|
102
|
+
## Follow-up browser journey and next gate
|
|
103
|
+
|
|
104
|
+
The schema gate above is now covered by scenario 8. A fresh inventory confirmed
|
|
105
|
+
four previously failed tabs and one responsive existing tab (8). No new tab was
|
|
106
|
+
opened. In that tab, the following actual UI journey completed:
|
|
107
|
+
|
|
108
|
+
1. Leave page editing, select reference record 235 and wait for its detail.
|
|
109
|
+
2. Enable editing and confirm the checked switch in a subsequent snapshot.
|
|
110
|
+
3. Leave editing, select record 193 (Ayla, also used in the earlier failure),
|
|
111
|
+
wait for detail and confirm that another DOM read succeeds.
|
|
112
|
+
4. Enable editing, open **Configurar formulário**, and confirm **Visualizar**
|
|
113
|
+
plus **Apresentação** selected in General settings.
|
|
114
|
+
5. Open **Layout**, inspect its populated sections/fields, cancel without
|
|
115
|
+
changes, and leave editing. Confirm no dialog, an unchecked switch and the
|
|
116
|
+
detail region still present. The tab was left available for visual review.
|
|
117
|
+
|
|
118
|
+
The final read-only configuration GET again matched version 92 exactly. This
|
|
119
|
+
journey did not save a page, edit employee data or modify a layout draft. It
|
|
120
|
+
proves successful interaction in this run; it does not explain previous crashed
|
|
121
|
+
tabs or establish lasting stability. The readonly resolved-runtime panel also
|
|
122
|
+
displayed `legacy CRUD fallback`; that label alone is not evidence that the
|
|
123
|
+
actual schema request fell back and should be checked against transport evidence
|
|
124
|
+
before being used diagnostically.
|
|
125
|
+
|
|
126
|
+
## Layout edit and cancellation proof
|
|
127
|
+
|
|
128
|
+
The next interactive gate also passed on September 8 in existing tab 8.
|
|
129
|
+
Classification of this follow-up: `docs-apenas`; no production code or test code
|
|
130
|
+
changed. The behavior is `ja-suportado-so-ux`: column movement, draft tracking,
|
|
131
|
+
discard confirmation and the data/presentation modes already have canonical
|
|
132
|
+
implementations. No additional contract was required.
|
|
133
|
+
|
|
134
|
+
Starting with record 193 selected and page editing off, the journey captured the
|
|
135
|
+
detail region's text and the Layout tab's text as comparison baselines. It then:
|
|
136
|
+
|
|
137
|
+
1. Enabled page editing and opened **Configurar formulário → Layout**.
|
|
138
|
+
2. Opened **Seção 1 → Linha 2 → Coluna 1 → Opções da coluna** and selected
|
|
139
|
+
**Mover para direita**. The draft then showed CPF before Nome Completo,
|
|
140
|
+
with both columns still at 6/12. Apply and Save became enabled.
|
|
141
|
+
3. Clicked **Cancelar**. The **Descartar rascunho não salvo** dialog appeared.
|
|
142
|
+
Choosing **Continuar editando** retained the changed field order.
|
|
143
|
+
4. Cancelled again and chose **Descartar rascunho**. Reopened the same editor:
|
|
144
|
+
the complete Layout tab text matched its initial baseline, including field
|
|
145
|
+
ordering. General settings showed **Sem alterações**, **Visualizar** and
|
|
146
|
+
**Apresentação** selected; the table still had record 193 selected.
|
|
147
|
+
5. Closed the unchanged editor and left editing. The complete detail-region text
|
|
148
|
+
matched its initial baseline, including the displayed values and their order.
|
|
149
|
+
The responsive tab was left in consultation mode for user review.
|
|
150
|
+
|
|
151
|
+
Read-only page configuration GETs before and after were structurally identical,
|
|
152
|
+
both at version 92 (`/tmp/praxis-layout-cancel-before.json` and
|
|
153
|
+
`/tmp/praxis-layout-cancel-after.json`). No Apply, Save or employee command was
|
|
154
|
+
used. These comparisons establish cancellation behavior for a menu-based column
|
|
155
|
+
move. They do not cover drag hit testing, discard after Apply, browser reload,
|
|
156
|
+
remote save/reopen, or every child storage key. The earlier eight automated
|
|
157
|
+
scenarios were not rerun for this documentation-only follow-up.
|
|
158
|
+
|
|
159
|
+
UX observation: the discard dialog explains that an already-applied preview is
|
|
160
|
+
retained, even in this journey where Apply was never used. That wording describes
|
|
161
|
+
the general behavior but introduces an unused state into the decision. If refined,
|
|
162
|
+
it should derive from the editor's existing applied/draft state and translation
|
|
163
|
+
resources; this run does not justify a new configuration flag or contract.
|
|
164
|
+
|
|
165
|
+
The isolated Apply/Save/reopen gate subsequently completed; see
|
|
166
|
+
[the operational proof](./layout-apply-save-reopen-2026-09-08.md). It confirms both
|
|
167
|
+
column moves, modes and page versioning, while recording a separate pointer
|
|
168
|
+
selection inconsistency after reload. That radio behavior was subsequently
|
|
169
|
+
isolated and corrected; see
|
|
170
|
+
[the Table selection proof](../../praxis-table/test-dev/radio-pointer-selection-2026-09-08.md).
|
|
171
|
+
The eight integration scenarios passed again, with the resource-schema scenario
|
|
172
|
+
now activating Material's touch target. The retained copy also passed live
|
|
173
|
+
pointer/keyboard/row selection after correcting an undeclared Rich Content input
|
|
174
|
+
introduced during fixture preparation. The original version 92 remained intact.
|
|
175
|
+
The remaining broader gate is the complete Page Builder host journey; the lab
|
|
176
|
+
proof does not certify that host or explain earlier browser crashes. Capture any
|
|
177
|
+
recurring failure before changing runtime, without removing customization, draft
|
|
178
|
+
preservation or field configuration to mask it.
|
|
179
|
+
|
|
180
|
+
No public API, generated manifest, HTTP corpus or installed skill changed.
|
|
181
|
+
Existing skills already require canonical sources and exact coverage statements;
|
|
182
|
+
this investigation adds evidence rather than a new runtime rule.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Schema loading: timeout, cancellation and recovery
|
|
2
|
+
|
|
3
|
+
## Owner and configuration
|
|
4
|
+
|
|
5
|
+
Schema transport policy belongs to Core. Dynamic Form consumes the existing
|
|
6
|
+
`SchemaMetadataClient` through `SCHEMA_METADATA_CLIENT_OPTIONS`; there is no
|
|
7
|
+
widget-specific timeout input or JSON property. A host configures the provider:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { SCHEMA_METADATA_CLIENT_OPTIONS } from '@praxisui/core';
|
|
11
|
+
|
|
12
|
+
{ provide: SCHEMA_METADATA_CLIENT_OPTIONS, useValue: { requestTimeoutMs: 15000 } }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The shared Core default is 30,000 ms. An explicit zero disables the deadline;
|
|
16
|
+
cancellation remains available. Core also owns transport error names:
|
|
17
|
+
`TimeoutError` and `AbortError`. The Form legacy Observable schema adapter uses
|
|
18
|
+
the same configured deadline and unsubscribes when cancelled.
|
|
19
|
+
|
|
20
|
+
## Runtime behavior
|
|
21
|
+
|
|
22
|
+
A schema timeout reaches the existing recoverable initialization error surface.
|
|
23
|
+
The message is localized in the Form catalog. Retry starts a new initialization;
|
|
24
|
+
it does not silently replace the requested `/all` schema with the legacy
|
|
25
|
+
`/filter` schema after a timeout or cancellation.
|
|
26
|
+
|
|
27
|
+
Destroy, retry, mode changes, resource changes and explicit schema URL changes
|
|
28
|
+
cancel the outstanding schema reads. Initialization generations prevent an older
|
|
29
|
+
configuration read, schema result, error handler or finally block from modifying
|
|
30
|
+
the replacement initialization. The saved page layout is retained for retry and
|
|
31
|
+
reconciled with the canonical schema after a successful response.
|
|
32
|
+
|
|
33
|
+
## Scope and limitations
|
|
34
|
+
|
|
35
|
+
This is transport resilience. During the investigation, the backend returned
|
|
36
|
+
HTTP 200 to the exact schema URL while the internal browser reported
|
|
37
|
+
`ERR_BLOCKED_BY_CLIENT`. A recoverable timeout does not remove that client block
|
|
38
|
+
and must not be reported as correcting its origin.
|
|
39
|
+
|
|
40
|
+
The deadline does not bound all initialization work. Hook execution keeps its
|
|
41
|
+
existing hook-registry policy. Diagnostic schema metadata persistence is not part
|
|
42
|
+
of the transport deadline; a non-transient host with stalled persistence can
|
|
43
|
+
still need separate investigation. Transient layout policy skips those writes.
|
|
44
|
+
No general initialization budget or local business rule was introduced.
|
|
45
|
+
|
|
46
|
+
## Focused validation
|
|
47
|
+
|
|
48
|
+
`praxis-dynamic-form.schema-loading.spec.ts` covers pending schema → localized
|
|
49
|
+
error → retry, no timeout fallback to a different schema contract, destroy,
|
|
50
|
+
late schema results, and late saved configuration after superseding initialization.
|
|
51
|
+
The fixtures use the existing sections-only `input-first` path so reconciliation
|
|
52
|
+
cannot swallow the timeout and report success with missing field metadata.
|
|
53
|
+
Transport fetch cancellation and concurrent-consumer behavior are tested in Core.
|
|
54
|
+
Live browser and integrated package builds are recorded by the integration review.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
The focal schema-loading, external-config-hydration and entity-selection run
|
|
58
|
+
passed 29 tests (`/private/tmp/praxis-form-schema-loading-tests.log`). This run
|
|
59
|
+
includes the error/retry DOM and isolated service fixtures; it does not claim
|
|
60
|
+
live network or production publication validation.
|
|
61
|
+
|
|
62
|
+
### Non-cooperative custom transports
|
|
63
|
+
|
|
64
|
+
The canonical Core transport reports `AbortError` on cancellation. Two additional
|
|
65
|
+
regressions exercise a transport that ignores cancellation and later rejects with
|
|
66
|
+
a generic error, through both generated-config and host-config initialization.
|
|
67
|
+
The inner construction error handlers validate the initialization generation
|
|
68
|
+
before changing UI state, so the old error cannot stop the newer loading state.
|
|
69
|
+
The late-success and late-error paths are covered independently.
|
|
70
|
+
|
|
71
|
+
The two generic late-error cases failed before the guard (`2 FAILED, 5 SUCCESS`)
|
|
72
|
+
and all seven schema-loading tests passed afterwards. Logs:
|
|
73
|
+
`/private/tmp/praxis-form-late-schema-rejection-red.log` and
|
|
74
|
+
`/private/tmp/praxis-form-late-schema-rejection-green.log`.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Section spacing: canonical eligibility and clear copy
|
|
2
|
+
|
|
3
|
+
Classification: `local-pequena`, owned by Dynamic Form's layout editor.
|
|
4
|
+
Adherence: `ja-suportado-mal-nomeado-ou-mal-materializado`. Core already defines
|
|
5
|
+
`FormSection.gapBottom` as space after the entire section. The Form runtime reads
|
|
6
|
+
that field; no contract, runtime spacing rule, backend or public API changed.
|
|
7
|
+
|
|
8
|
+
The toolbar described column spacing but wrote section `gapBottom`. Eligibility
|
|
9
|
+
depended on a noncanonical `gapCustomized` marker rather than the existing value,
|
|
10
|
+
so an explicitly authored gap without that marker could be overwritten. New
|
|
11
|
+
sections and bulk updates also generated the marker despite the JSON API guide
|
|
12
|
+
warning that it was not stable configuration.
|
|
13
|
+
|
|
14
|
+
The command now fills only absent/null `gapBottom`, preserves explicit values
|
|
15
|
+
(including zero), and emits nothing when no sections are eligible. It no longer
|
|
16
|
+
generates or consults the old marker; unrelated unknown properties in a loaded
|
|
17
|
+
document are not bulk-migrated by this operation. Non-finite proposed numbers
|
|
18
|
+
are rejected. Changing the proposed value alone still does not emit config.
|
|
19
|
+
The existing output-to-input host flow commits the emitted draft.
|
|
20
|
+
|
|
21
|
+
Labels, tooltips and accessible names use the layout editor i18n catalog in
|
|
22
|
+
pt-BR/en-US. **Espaço após as seções** and **Preencher espaços não definidos**
|
|
23
|
+
explain the scope and distinguish this command from editor-only density/guides.
|
|
24
|
+
Existing icons, control styling and theme tokens are retained.
|
|
25
|
+
|
|
26
|
+
## Browser proof
|
|
27
|
+
|
|
28
|
+
On `/page-builder-ia`, selected Ayla, opened the Form editor and Layout, and
|
|
29
|
+
captured the rendered Layout baseline. Entering 24 kept **Sem alterações** and
|
|
30
|
+
disabled Apply/Save. Invoking **Preencher espaços não definidos** enabled
|
|
31
|
+
Apply/Save and disabled the fill command. Reading the actual JSON editor showed
|
|
32
|
+
the canonical editor envelope with `gapBottom: 24` on the four previously unset
|
|
33
|
+
sections and no `gapCustomized` property.
|
|
34
|
+
|
|
35
|
+
Cancelled, confirmed discard and reopened Layout on the same page. Its full
|
|
36
|
+
rendered text exactly matched the baseline. No Apply, component Save, page Save
|
|
37
|
+
or employee write was performed. Screenshot review covered the dark desktop
|
|
38
|
+
editor, expanded and reduced panels; the new label wrapped without overlap.
|
|
39
|
+
This is not mobile or full screen-reader certification. The runtime effect of
|
|
40
|
+
gapBottom was not newly changed or certified through a persisted save.
|
|
41
|
+
|
|
42
|
+
## Validation and artifacts
|
|
43
|
+
|
|
44
|
+
The focused toolbar/editor suite adds explicit spacing, zero, fill-once,
|
|
45
|
+
non-finite values, no empty emission and marker-free section creation checks.
|
|
46
|
+
The first compile required a fixture assertion to acknowledge EventEmitter's
|
|
47
|
+
optional value argument; no production typing was relaxed.
|
|
48
|
+
Logs: `/tmp/praxis-section-spacing-tests-final.log` and
|
|
49
|
+
`/tmp/praxis-section-spacing-build.log`.
|
|
50
|
+
Final result: **41 tests passed** and `npm run build:praxis-dynamic-form`
|
|
51
|
+
succeeded through the official dependency/build closure. A final Config API
|
|
52
|
+
GET matched the prior receipt exactly, including version 92 and ETag:
|
|
53
|
+
`/tmp/praxis-section-spacing-config-after.json`. The existing port 4003 server
|
|
54
|
+
remains available; no new server or interactive shell was started.
|
|
55
|
+
|
|
56
|
+
README and the owning JSON API guide were corrected together. The existing Form
|
|
57
|
+
authoring manifest does not declare the removed marker or a separate bulk-fill
|
|
58
|
+
contract; no manifest input, operation or path changed. Public-site examples,
|
|
59
|
+
HTTP corpus and registry generation require no new artifact for this editor
|
|
60
|
+
correction. Existing skills already require canonical layout semantics and
|
|
61
|
+
draft isolation; no skill guidance diverged and no sync was necessary.
|