@praxisui/dynamic-form 9.0.67 → 9.0.68-rc.0

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 CHANGED
@@ -258,6 +258,14 @@ Recommended defaults:
258
258
  - dense command drawers: `helpPresentation.display = "auto"` with popover preference for select, checkbox, toggle, date and numeric controls;
259
259
  - operational input-heavy forms: `fieldIconPolicy = "presentation-only"` unless the icon is part of the actual affordance.
260
260
 
261
+ `layoutPolicy.persistence = "transient"` also suppresses automatic UI-storage
262
+ writes of derived schema metadata and its context index. Schema fields, hashes,
263
+ context and verification state remain available in memory. Pending metadata work
264
+ rechecks the policy before sending a write; this does not cancel requests already
265
+ sent. Existing storage reads and explicit editor Apply/Save behavior are unchanged.
266
+ `configPersistenceStrategy = "input-first"` alone controls precedence, not this
267
+ no-automatic-write policy. The default persistent behavior is unchanged.
268
+
261
269
  On narrow viewports, the standard form action footer stacks validation guidance
262
270
  above the command CTA and keeps the action full width. This is presentation
263
271
  behavior only; submit labels, visibility and confirmation still come from the
@@ -303,6 +311,24 @@ Common inputs:
303
311
  - `domainRules`
304
312
  - `editorialContext`
305
313
 
314
+ `providePraxisDynamicFormMetadata()` also registers localized editorial copy through
315
+ the existing `ComponentMetadataRegistry`. Shared editors resolve labels and help
316
+ with `resolveEditorial('praxis-dynamic-form')`, while raw input names, types and
317
+ defaults remain authoritative. The form owns the pt-BR/en-US dictionaries. Hosts
318
+ can override keys such as `praxisDynamicForm.editorial.mode.label` using the normal
319
+ Praxis i18n provider/translator; consuming builders need no form-specific map.
320
+ Advanced inputs without editorial overrides retain their raw metadata copy.
321
+
322
+ Surface action editors in custom actions, command rules and section headers
323
+ propagate invalid JSON drafts into the owner's dirty/valid state. Apply/Save stays
324
+ blocked until all errors are corrected; tab navigation preserves raw text and
325
+ Reset explicitly discards it. See [consumer validation](../praxis-core/docs/surface-draft-consumers-validation-2026-09-08.md).
326
+
327
+ In the actions editor, omitted optional text (icons, shortcuts, tooltips and CSS
328
+ classes) is displayed as an empty input. Opening a tab does not write empty
329
+ strings into the configuration; existing host text and explicit user edits retain
330
+ their values.
331
+
306
332
  `actions` is also a registered Dynamic Page input. A host or surface
307
333
  materializer may use it for presentation affordances such as a contextual
308
334
  submit label and button visibility. It must not use that input to replace the
@@ -322,6 +348,19 @@ by local master-detail/detail surfaces. With a remote read source, the backend
322
348
  entity remains canonical; a later `initialValue` change never resets hydrated
323
349
  fields or pending user edits. Change `resourceId` to load another remote entity.
324
350
 
351
+ During a remote entity read, the form preserves its layout and mounted controls,
352
+ but hides the previous values from sight, keyboard interaction and assistive
353
+ technology. A local status explains the update. Failed or invalid reads keep the
354
+ body and submit blocked and offer a local retry for the same identity. Successful
355
+ reads replace the record snapshot, clearing fields omitted by the new response;
356
+ superseded reads cannot apply to the current selection. This is automatic runtime
357
+ behavior, not an additional widget binding or editor setting. Creation commands
358
+ and authoritative local `initialValue` snapshots retain their existing behavior.
359
+ Hiding is immediate: an opacity transition must not reveal the previous identity
360
+ under the new header. Explicit retry focuses a stable detail region; the response
361
+ does not steal focus after the user navigates elsewhere. See the
362
+ [local feedback contract and evidence](docs/entity-read-feedback.md).
363
+
325
364
  For local master-detail views, `emptyState` is the canonical opt-in placeholder
326
365
  while neither `resourceId` nor a non-empty `initialValue` identifies a record.
327
366
  The Dynamic Form replaces its field surface with the shared
@@ -331,6 +370,14 @@ the component owns the deterministic transition between "select a record" and
331
370
  the presentation-only form. Do not duplicate that state with a consumer-local
332
371
  card or keep an empty form visible behind it.
333
372
 
373
+ The placeholder follows its content height, without reserving a fraction of the
374
+ viewport. Its existing `--pdx-form-context-empty-min-height` and
375
+ `--pdx-form-context-empty-padding` tokens default to `0`; the shared card still
376
+ provides its internal spacing. Hosts can override those tokens to reserve more
377
+ space. `--pdx-form-context-empty-max-width` continues to default to `32rem`.
378
+ Visual choices such as alignment, density and icon container remain in
379
+ `emptyState`, including the native editor and JSON document.
380
+
334
381
  ```html
335
382
  <praxis-dynamic-form
336
383
  mode="view"
@@ -590,3 +637,98 @@ O botão criado em **Configurar widget → Ações rápidas (inputs)** continua
590
637
  - **Geral → Dados do formulário** separates **Criar / Editar / Visualizar** from **Automático / Campos / Apresentação**. Selecting presentation in Create/Edit keeps the operation unchanged and explains the inactive state with an explicit action to switch to View.
591
638
  - **Estilo da apresentação** remains discoverable regardless of the current mode. It previews sample data and does not activate presentation by itself. Filter Form does not expose this tab because it has no presentation runtime.
592
639
  - Applying or finishing widget editing updates the page draft. **Salvar página** persists the composition. Shortening sample text affects the preview only.
640
+
641
+
642
+ ### Limpeza de seleção em detalhes controlados
643
+
644
+ Em formulários `view`/`edit` ligados a uma identidade remota, mudar `resourceId` de um registro para `null` limpa o snapshot anterior e cancela a leitura pendente, inclusive quando ela usa `readUrl`. Respostas de seleções substituídas não podem hidratar o registro atual. Um rebuild de configuração após essa limpeza não restaura o cache nem a semente `initialValue` do registro anterior; uma nova identidade inicia sua própria hidratação. Isso não altera snapshots locais authorados por `initialValue`, nem os defaults de comandos em modo `create`.
645
+
646
+
647
+ ### Recoverable schema loading
648
+
649
+ Dynamic Form consumes Core's `SCHEMA_METADATA_CLIENT_OPTIONS` transport policy
650
+ for schema deadlines and cancellation. Timeouts use the existing error/retry
651
+ surface; superseded results cannot finish a newer initialization. There is no
652
+ additional widget timeout input. See [schema loading recovery](docs/schema-loading-recovery.md)
653
+ for provider configuration, scope, and validation limits.
654
+
655
+
656
+ ### Orientação antes da seleção de um registro
657
+
658
+ O editor nativo, em **Geral → Sem registro selecionado**, materializa o contrato existente `PraxisDynamicFormEmptyState` em `bindings.emptyState`. O wrapper Page Builder projeta esse binding para `inputs.emptyState`; Apply, Save e JSON usam o mesmo documento. Não pertence a `FormConfig` nem substitui o modo dos dados.
659
+
660
+ `title` é obrigatório e não pode conter apenas espaços. `description` e `icon` são textos opcionais; a cópia de negócio permanece literal, sem ser interpretada automaticamente como chave i18n. O seletor usa o catálogo canônico de ícones. Restaurar o ícone padrão limpa a escolha explícita. Os controles do editor usam o catálogo i18n Form; a aparência runtime usa os tokens do empty state compartilhado.
661
+
662
+ As opções de aparência ficam em disclosure avançado: `tone` (`neutral`, `primary`, `secondary`), `variant` (`card`, `inline`, `panel`, `transparent`), `alignment` (`start`, `center`), `density` (`compact`, `comfortable`) e `iconContainer` (`none`, `circle`, `soft`). Ausência de opção herda o padrão do componente; JSON inválido produz diagnóstico.
663
+
664
+ A orientação aparece somente em `mode=view`, sem registro selecionado nem snapshot local. Criar e Editar preservam a configuração sem exibi-la. Desligar grava `null`, que impede reativação por uma preferência antiga; substituir um documento que omite o binding também limpa a orientação. Em `input-first`, a página governa o valor. Filter Form não expõe essa seção, pois não possui contexto de seleção equivalente.
665
+
666
+ Após Aplicar, o dono da página confirma o commit local pelo canal transitório de sessão `appliedValues$`. O wrapper/nativo usa `acceptAppliedValue` para comparar o draft com a última prévia aceita; retornar aos valores de abertura volta a habilitar Aplicar quando a prévia diverge. Redefinir continua restaurando a abertura do Form. A confirmação local não comprova persistência HTTP.
667
+
668
+ O wrapper isola `SETTINGS_PANEL_DATA` do editor embutido: o envelope do host e seus observables nunca são clonados como configuração. O Core envia o canal de confirmação apenas a editores que declaram o input `appliedValues$`; o editor nativo consome esse canal somente junto ao documento canônico.
669
+
670
+ ### Leitura do editor de layout
671
+
672
+ **Espaço após as seções** define o valor proposto para `gapBottom`, em pixels. Alterar o número não modifica o formulário. **Preencher espaços não definidos** leva o valor ao rascunho somente nas seções sem espaçamento explícito; valores existentes, inclusive zero, são preservados. O comando não cria uma marca paralela de personalização. Aplicar/Salvar continuam confirmando o rascunho; o controle não altera o espaço entre colunas.
673
+
674
+ **Densidade do editor** (Compacta, Confortável e Espaçosa) e **Guias do editor** (Bordas das seções e Separadores) ajustam somente a visualização de trabalho. Não alteram o documento nem habilitam Aplicar/Salvar. Os controles mantêm nomes acessíveis, estados selecionado/pressionado e dicas explicativas no catálogo `praxisDynamicFormLayoutEditor`, com português, inglês e substituição pelo tradutor do host. Os valores internos e os tokens visuais existentes permanecem os mesmos.
675
+
676
+ **Renomear seção**, no cabeçalho, edita somente o título. **Salvar nome** ou Enter confirma; Cancelar ou Escape descarta a edição do nome e devolve o foco ao botão. Nomes vazios são recusados. Aparência, descrição, ícone e comportamento continuam no editor completo da seção. Uma seção sem linhas orienta a sequência linha → colunas → campos e oferece **Adicionar primeira linha**, usando o comando existente. Os textos usam o catálogo i18n da lib e a aparência herda tokens do host. Remover uma seção preserva os metadados dos campos: os campos elegíveis sem outro posicionamento voltam ao catálogo; blocos visuais pertencentes à seção são removidos com sua estrutura. Essas alterações continuam sujeitas a Aplicar/Salvar do editor e Salvar página.
677
+
678
+ O botão de ações de cada linha mostra seu número e possui nome acessível com linha e seção. O menu mantém os presets, Adicionar coluna e Remover linha existentes, utilizando o comportamento de teclado e foco do menu Material.
679
+
680
+ Os controles de espaçamento e faixa de tela ficam em **Ajustar layout da linha**, recolhidos inicialmente; abrir esse grupo não altera o documento. O menu da linha sempre atua na linha, independentemente da seleção anterior. Presets mostram miniaturas proporcionais e nomes traduzidos. A distribuição de larguras afeta somente a faixa exibida (por padrão MD); a estrutura de colunas é compartilhada pelas faixas. Ao reduzir colunas, seus itens são anexados em ordem à última coluna mantida, preservando campos e blocos visuais. As larguras das demais faixas nas colunas mantidas permanecem inalteradas.
681
+
682
+ Selecionar um campo mostra sua localização usando o título da seção e o rótulo dos metadados. As ações **Editar campo** e **Layout da coluna** abrem os editores canônicos existentes; selecionar ou abrir um editor não modifica o documento. Enter e Espaço selecionam o campo focado. As ações são suprimidas quando o alvo não existe mais na estrutura canônica.
683
+
684
+ Para posicionar um campo disponível sem arrastar, abra **Opções da coluna → Adicionar campo da API**, navegue com as setas e confirme com Enter. O campo sai do catálogo de disponíveis e recebe foco na coluna; Tab continua para editar seus metadados. Isso posiciona um campo já definido, sem criar ou duplicar metadados. Campos já posicionados não podem ser reinseridos por esse comando. A coluna vazia e o catálogo explicam esse caminho usando o catálogo i18n da lib.
685
+
686
+ Em colunas mistas, esse comando acrescenta o campo ao final de `items[]`, inclusive depois de blocos visuais. Os itens anteriores conservam identidade e conteúdo. Para escolher outra posição, use **Mover campo**; a posição considera também os blocos visuais. `fields[]` permanece uma projeção apenas dos campos, sem incluir conteúdo editorial.
687
+
688
+ Nas opções de movimentação, blocos visuais mostram a posição original na coluna e um resumo do conteúdo, por exemplo **bloco visual (posição 2): Revise as informações…**. O número conta todos os itens, inclusive o campo sendo movido; não é um identificador persistido. Textos iguais e blocos vazios são diferenciados pela posição. O resumo reutiliza a leitura textual do editor, normaliza espaços e limita a prévia a 80 caracteres; não avalia bindings nem renderiza HTML. Os valores das opções continuam sendo IDs canônicos.
689
+
690
+ Na prévia de um bloco visual, Enter abre a edição do conteúdo e Espaço seleciona o bloco. Botões internos conservam sua própria ativação pelo teclado: abrir o menu ou remover o bloco não deve disparar o editor de conteúdo. Ao inserir ou mover um bloco, o foco acompanha a prévia selecionada; ao removê-lo, retorna à coluna preservada. O editor não recupera esse foco se a seleção mudar antes da renderização.
691
+
692
+ **Mover campo** abre a escolha de seção, linha, coluna e posição sem depender do arraste. Linhas e colunas mostram um resumo dos primeiros três itens, com a quantidade restante quando necessário. Os rótulos vêm de `fieldMetadata`, com nome técnico como fallback; blocos visuais e destinos vazios são identificados. Os resumos descrevem a estrutura authorada, incluindo campos ocultos, e não simulam permissões ou visibilidade runtime. A posição considera todos os itens da coluna, incluindo blocos visuais. O serviço de layout é isolado por instância do editor, para que operações do rascunho não sejam transmitidas aos formulários em uso. Abrir ou cancelar não altera o documento; confirmar utiliza `DynamicFormLayoutService.moveLayoutItemById`, conserva a identidade do item, seus metadados e os contêineres vazios, e seleciona/foca o campo no destino. A aparência passa a ser a da coluna de destino. Se o documento for substituído enquanto o diálogo estiver aberto, a movimentação é recusada com orientação para escolher novamente. Aplicar, Salvar e fechar e Salvar página mantêm suas responsabilidades existentes.
693
+
694
+ Na aba **Estilo** da coluna, o alinhamento é vertical na linha (`align-self`), não alinhamento de texto. O grupo visual Topo/Centro/Base/Preencher mantém os valores canônicos `start`/`center`/`end`/`stretch`. **Espaço interno** apresenta o `padding` numérico existente em pixels; o editor mantém sua faixa de 0 a 32. Classe CSS do host e identificador de teste ficam em **Integração com o aplicativo**, recolhidos inicialmente. Expandir esse grupo não limpa seus valores nem modifica o documento; os controles usam i18n da lib e tokens Material/Praxis existentes.
695
+
696
+ O painel de coluna identifica seu alvo por seção, linha e número da coluna no título. Os campos aparecem com os rótulos de `fieldMetadata`, seguindo a ordem canônica de `items`; nomes técnicos são fallback quando não existe rótulo. Esse contexto é transitório e não entra no JSON salvo. As faixas XS–XL mantêm seus códigos e ganham nomes traduzidos e explicação da herança. Largura e recuo ficam juntos; **Ordem visual da coluna** é recolhida inicialmente e aberta quando há erro de ordem. Abrir grupos ou trocar a faixa de prévia não modifica o formulário.
697
+
698
+ O editor da coluna apresenta uma prévia de 12 partes, derivada da largura e do recuo resolvidos para a faixa selecionada. Ela representa a coluna isolada, não a distribuição completa da linha. **Modelos para várias faixas de tela** separa os presets responsivos dos ajustes de largura/recuo: o grupo informa quais modelos também afetam visibilidade e estilo. **Usar valores atuais em todas as faixas** copia largura, recuo, ordem e visibilidade; não restaura valores iniciais. Valores sem definição própria continuam seguindo a herança responsiva canônica.
699
+
700
+ Largura aceita inteiros de 1 a 12, recuo de 0 a 11 e ordem de -12 a 12. Limpar um valor mantém a herança responsiva; não equivale a zero. Valores inválidos permanecem visíveis para correção, com erro traduzido por propriedade/faixa, e bloqueiam Aplicar/Salvar, a prévia e os resumos numéricos. A edição JSON valida esses mesmos domínios novamente no momento de aplicar. **Ocultar em mobile** e **Somente desktop** alteram apenas visibilidade: preservam largura, recuo, ordem e estilo, inclusive em colunas personalizadas.
701
+
702
+
703
+
704
+
705
+
706
+ Os rótulos Largura, Recuo e Faixa de tela apresentam os contratos existentes `span`, `offset` e breakpoint; não mudam o documento salvo. Colunas também podem ser reorganizadas pelo menu Mover para esquerda/direita. O resumo de espaçamento distingue valor herdado de zero explícito, exibindo px somente para números.
707
+
708
+ O indicador “Oculto nos metadados” aparece quando `FieldMetadata.hidden` ou `FieldMetadata.formHidden` é explicitamente true. Ele é informativo, usa a tradução do editor e os tokens de texto do tema. Não avalia `hiddenCondition`, permissões ou visibilidade da coluna, nem altera esses contratos. A ausência desse indicador não é garantia de visibilidade no runtime.
709
+
710
+
711
+ ### Row spacing guidance in the layout editor
712
+
713
+ The row inspector treats unused grid space as an intentional authoring choice,
714
+ not a requirement to fill all 12 units. Guidance includes offsets and respects
715
+ inherited visibility at the selected preview breakpoint. Columns containing only
716
+ fields with static `hidden: true` or `formHidden: true` do not contribute; rich
717
+ content, mixed visible content, unknown field references and empty draft columns
718
+ remain available for planning.
719
+
720
+ The optional width suggestion uses the same occupancy calculation. Inspecting a
721
+ row or changing its preview breakpoint does not change its document. This is
722
+ static authoring guidance, not a simulation of record-dependent rules, schema
723
+ hydration or permission decisions. Numeric domain validation and Apply/Save
724
+ validation remain separate and unchanged.
725
+
726
+
727
+ ### Navegação em painéis estreitos
728
+
729
+ A adaptação de authoring considera a largura do contêiner, inclusive quando o
730
+ painel é estreito em uma janela desktop. Table e Dynamic Form exibem “Seção do
731
+ editor” até 768px de largura disponível, mantendo a mesma seleção e os conteúdos
732
+ das abas. Acima desse limite, reaparece a navegação por abas. O Settings Panel
733
+ organiza título, expandir e fechar em uma grade até 599px; a prévia, quando
734
+ suportada, ocupa a linha seguinte. Nenhum documento ou protocolo de Save é alterado.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-09-07T00:54:55.301Z",
3
+ "generatedAt": "2026-09-09T10:03:24.330Z",
4
4
  "packageName": "@praxisui/dynamic-form",
5
- "packageVersion": "9.0.67",
5
+ "packageVersion": "9.0.68-rc.0",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -6636,8 +6636,8 @@
6636
6636
  },
6637
6637
  {
6638
6638
  "name": "emptyState",
6639
- "type": "PraxisDynamicFormEmptyState",
6640
- "description": "Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host."
6639
+ "type": "PraxisDynamicFormEmptyState | null",
6640
+ "description": "Authorado em bindings.emptyState no editor; null desliga explicitamente. Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host."
6641
6641
  },
6642
6642
  {
6643
6643
  "name": "readUrl",
@@ -7545,7 +7545,7 @@
7545
7545
  "type": "string"
7546
7546
  },
7547
7547
  "span": {
7548
- "type": "number",
7548
+ "type": "integer",
7549
7549
  "minimum": 1,
7550
7550
  "maximum": 12,
7551
7551
  "default": 6
@@ -9620,9 +9620,9 @@
9620
9620
  {
9621
9621
  "chunkIndex": 42,
9622
9622
  "chunkKind": "authoring_manifest",
9623
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"showAiAssistant\",\"type\":\"boolean\",\"description\":\"Mostra os gatilhos do copiloto semantico Praxis\"},{\"name\":\"config\",\"type\":\"FormConfig\",\"description\":\"Configuração do formulário; sections é opcional em forms schema-driven e não deve ser criado como array vazio apenas para satisfazer TypeScript.\"},{\"name\":\"actions\",\"type\":\"FormConfig['actions'] | null\",\"description\":\"Overrides de apresentação da barra de ações fornecidos pelo host sem substituir o contrato HTTP da surface.\"},{\"name\":\"formId\",\"type\":\"string\",\"description\":\"Identidade estável usada pelo runtime para persistência local da configuração.\"},{\"name\":\"resourcePath\",\"type\":\"string\",\"description\":\"Caminho do recurso (API)\"},{\"name\":\"resourceId\",\"type\":\"string | number | null\",\"description\":\"Identidade canônica do registro carregado em modos edit e view.\"},{\"name\":\"emptyState\",\"type\":\"PraxisDynamicFormEmptyState\",\"description\":\"Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host.\"},{\"name\":\"readUrl\",\"type\":\"string\",\"description\":\"Endpoint canonico de leitura para surfaces VIEW/READ_PROJECTION\"},{\"name\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\"],\"description\":\"Modo de operação\"},{\"name\":\"presentation\",\"type\":\"DynamicFormPresentationSnapshot | null\",\"description\":\"Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal.\"},{\"name\":\"presentationModeGlobal\",\"type\":\"boolean | null\",\"description\":\"Preferência de exibição, também authorada em bindings.presentationModeGlobal: true apresenta rótulos e valores somente em mode=view; false força campos; null/ausência segue layoutPolicy. Não altera o modo dos dados.\"},{\"name\":\"configPersistenceStrategy\",\"type\":\"string\",\"allowedValues\":[\"local-first\",\"input-first\"],\"description\":\"Precedência entre configuração persistida e contrato explícito do host. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor.\"},{\"name\":\"generatedLayoutPreset\",\"type\":\"string\",\"allowedValues\":[\"default\",\"compactPresentation\"],\"description\":\"Preset usado apenas ao gerar a configuracao inicial a partir de metadata/schema; nao reprocessa layouts persistidos ou autorados.\"},{\"name\":\"layoutPolicy\",\"type\":\"DynamicFormLayoutPolicy\",\"description\":\"Politica opt-in para layout schema-driven transient. Use source=schema apenas quando o backend schema for a fonte canonica do agrupamento; use detailSummary para seleção de campos e densidade responsiva do resumo read-only compacto sem FormConfig.sections locais. Quando o resumo precisar vencer x-ui.width publicado para outras surfaces, use detailSummary.widthPrecedence=summary. Em groupedCommand, orphanFieldExpansion governa linhas lógicas com um unico campo; partialRowStrategy=fill-compatible projeta spans compatíveis depois de resolver visibilidade responsiva, CSS order e wrap, sem alterar x-ui.width ou persistir sections; contextFields identifica campos do request hidratados pela surface que permanecem no payload sem criar controles redundantes.\"},{\"name\":\"fieldIconPolicy\",\"type\":\"string\",\"allowedValues\":[\"all\",\"presentation-only\",\"none\"],\"description\":\"Politica visual do host para icones prefix/suffix de campos vindos da metadata. Use presentation-only para manter icones decorativos em apresentacao e ocultar em controles tradicionais.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Habilita edição visual\"}]}",
9623
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"showAiAssistant\",\"type\":\"boolean\",\"description\":\"Mostra os gatilhos do copiloto semantico Praxis\"},{\"name\":\"config\",\"type\":\"FormConfig\",\"description\":\"Configuração do formulário; sections é opcional em forms schema-driven e não deve ser criado como array vazio apenas para satisfazer TypeScript.\"},{\"name\":\"actions\",\"type\":\"FormConfig['actions'] | null\",\"description\":\"Overrides de apresentação da barra de ações fornecidos pelo host sem substituir o contrato HTTP da surface.\"},{\"name\":\"formId\",\"type\":\"string\",\"description\":\"Identidade estável usada pelo runtime para persistência local da configuração.\"},{\"name\":\"resourcePath\",\"type\":\"string\",\"description\":\"Caminho do recurso (API)\"},{\"name\":\"resourceId\",\"type\":\"string | number | null\",\"description\":\"Identidade canônica do registro carregado em modos edit e view.\"},{\"name\":\"emptyState\",\"type\":\"PraxisDynamicFormEmptyState | null\",\"description\":\"Authorado em bindings.emptyState no editor; null desliga explicitamente. Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host.\"},{\"name\":\"readUrl\",\"type\":\"string\",\"description\":\"Endpoint canonico de leitura para surfaces VIEW/READ_PROJECTION\"},{\"name\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\"],\"description\":\"Modo de operação\"},{\"name\":\"presentation\",\"type\":\"DynamicFormPresentationSnapshot | null\",\"description\":\"Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal.\"},{\"name\":\"presentationModeGlobal\",\"type\":\"boolean | null\",\"description\":\"Preferência de exibição, também authorada em bindings.presentationModeGlobal: true apresenta rótulos e valores somente em mode=view; false força campos; null/ausência segue layoutPolicy. Não altera o modo dos dados.\"},{\"name\":\"configPersistenceStrategy\",\"type\":\"string\",\"allowedValues\":[\"local-first\",\"input-first\"],\"description\":\"Precedência entre configuração persistida e contrato explícito do host. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor.\"},{\"name\":\"generatedLayoutPreset\",\"type\":\"string\",\"allowedValues\":[\"default\",\"compactPresentation\"],\"description\":\"Preset usado apenas ao gerar a configuracao inicial a partir de metadata/schema; nao reprocessa layouts persistidos ou autorados.\"},{\"name\":\"layoutPolicy\",\"type\":\"DynamicFormLayoutPolicy\",\"description\":\"Politica opt-in para layout schema-driven transient. Use source=schema apenas quando o backend schema for a fonte canonica do agrupamento; use detailSummary para seleção de campos e densidade responsiva do resumo read-only compacto sem FormConfig.sections locais. Quando o resumo precisar vencer x-ui.width publicado para outras surfaces, use detailSummary.widthPrecedence=summary. Em groupedCommand, orphanFieldExpansion governa linhas lógicas com um unico campo; partialRowStrategy=fill-compatible projeta spans compatíveis depois de resolver visibilidade responsiva, CSS order e wrap, sem alterar x-ui.width ou persistir sections; contextFields identifica campos do request hidratados pela surface que permanecem no payload sem criar controles redundantes.\"},{\"name\":\"fieldIconPolicy\",\"type\":\"string\",\"allowedValues\":[\"all\",\"presentation-only\",\"none\"],\"description\":\"Politica visual do host para icones prefix/suffix de campos vindos da metadata. Use presentation-only para manter icones decorativos em apresentacao e ocultar em controles tradicionais.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Habilita edição visual\"}]}",
9624
9624
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-dynamic-form-authoring-manifest.ts",
9625
- "contentHash": "e7860094c6eee151ca66581a5fbb44d907d03a604cbc85e50789f38505ca6064",
9625
+ "contentHash": "71de795e514367583af30f004099e53c0376010d58718a6b73935e544a090303",
9626
9626
  "sourceKind": "component_definition",
9627
9627
  "sourceId": "praxis-dynamic-form",
9628
9628
  "corpusVersion": "1.0.0"
@@ -9650,9 +9650,9 @@
9650
9650
  {
9651
9651
  "chunkIndex": 45,
9652
9652
  "chunkKind": "authoring_manifest",
9653
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"field.submitPolicy.set\",\"title\":\"Definir política de submissão do campo\",\"scope\":\"field\",\"targetKind\":\"localField\",\"target\":{\"kind\":\"localField\",\"resolver\":\"field-by-name\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"submitPolicy\"],\"properties\":{\"submitPolicy\":{\"enum\":[\"omit\",\"include\",\"includeWhenDirty\"]}}},\"effects\":[{\"kind\":\"merge-by-key\",\"path\":\"fieldMetadata[]\",\"key\":\"name\"}],\"validators\":[\"field-exists\",\"field-is-local\",\"editor-round-trip-preserve\"],\"affectedPaths\":[\"fieldMetadata[].submitPolicy\"],\"submissionImpact\":\"affects-submission\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.visualBlock.add\",\"title\":\"Adicionar bloco visual\",\"scope\":\"column\",\"targetKind\":\"column\",\"target\":{\"kind\":\"column\",\"resolver\":\"column-by-id-in-row\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"document\"],\"properties\":{\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\",\"required\":[\"kind\",\"version\",\"nodes\"],\"properties\":{\"kind\":{\"const\":\"praxis.rich-content\"},\"version\":{\"type\":\"string\"},\"nodes\":{\"type\":\"array\"}}},\"layout\":{\"enum\":[\"block\",\"inline\"],\"default\":\"block\"},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-visual-block-add\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\"],\"writes\":[\"sections[].rows[].columns[].items\"],\"identityKeys\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.sectionId\",\"target.rowId\",\"target.columnId\",\"id\",\"document\"],\"properties\":{\"target.sectionId\":{\"type\":\"string\"},\"target.rowId\":{\"type\":\"string\"},\"target.columnId\":{\"type\":\"string\"},\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\"},\"layout\":{\"enum\":[\"block\",\"inline\"]},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-layout-location-not-found\",\"duplicate-visual-block-id\",\"invalid-rich-content-document\"],\"description\":\"Adds a richContent layout item into sections[].rows[].columns[].items[] by stable section, row, and column ids.\"}}],\"validators\":[\"layout-target-exists\",\"visual-block-id-unique\",\"rich-content-document-valid\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
9653
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"field.submitPolicy.set\",\"title\":\"Definir política de submissão do campo\",\"scope\":\"field\",\"targetKind\":\"localField\",\"target\":{\"kind\":\"localField\",\"resolver\":\"field-by-name\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"submitPolicy\"],\"properties\":{\"submitPolicy\":{\"enum\":[\"omit\",\"include\",\"includeWhenDirty\"]}}},\"effects\":[{\"kind\":\"merge-by-key\",\"path\":\"fieldMetadata[]\",\"key\":\"name\"}],\"validators\":[\"field-exists\",\"field-is-local\",\"editor-round-trip-preserve\"],\"affectedPaths\":[\"fieldMetadata[].submitPolicy\"],\"submissionImpact\":\"affects-submission\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.visualBlock.add\",\"title\":\"Adicionar bloco visual\",\"scope\":\"column\",\"targetKind\":\"column\",\"target\":{\"kind\":\"column\",\"resolver\":\"column-by-id-in-row\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"document\"],\"properties\":{\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\",\"required\":[\"kind\",\"version\",\"nodes\"],\"properties\":{\"kind\":{\"const\":\"praxis.rich-content\"},\"version\":{\"type\":\"string\"},\"nodes\":{\"type\":\"array\"}}},\"layout\":{\"enum\":[\"block\",\"inline\"],\"default\":\"block\"},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-visual-block-add\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\"],\"writes\":[\"sections[].rows[].columns[].items\"],\"identityKeys\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.sectionId\",\"target.rowId\",\"target.columnId\",\"id\",\"document\"],\"properties\":{\"target.sectionId\":{\"type\":\"string\"},\"target.rowId\":{\"type\":\"string\"},\"target.columnId\":{\"type\":\"string\"},\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\"},\"layout\":{\"enum\":[\"block\",\"inline\"]},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-layout-location-not-found\",\"duplicate-visual-block-id\",\"invalid-rich-content-document\"],\"description\":\"Adds a richContent layout item into sections[].rows[].columns[].items[] by stable section, row, and column ids.\"}}],\"validators\":[\"layout-target-exists\",\"visual-block-id-unique\",\"rich-content-document-valid\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
9654
9654
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-dynamic-form-authoring-manifest.ts",
9655
- "contentHash": "167125364e267e04c128dc4d5d1fb1d7d137d0ed5b0c05cb8d13b5aac48b8d4c",
9655
+ "contentHash": "fece171cf8179191d5448ab3636e71b44d885256e63764ef75f11f002bef984c",
9656
9656
  "sourceKind": "component_definition",
9657
9657
  "sourceId": "praxis-dynamic-form",
9658
9658
  "corpusVersion": "1.0.0"
@@ -16855,7 +16855,7 @@
16855
16855
  "type": "string"
16856
16856
  },
16857
16857
  "span": {
16858
- "type": "number",
16858
+ "type": "integer",
16859
16859
  "minimum": 1,
16860
16860
  "maximum": 12,
16861
16861
  "default": 6
@@ -17480,9 +17480,9 @@
17480
17480
  {
17481
17481
  "chunkIndex": 32,
17482
17482
  "chunkKind": "authoring_manifest",
17483
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
17483
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
17484
17484
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-filter-form-authoring-manifest.ts",
17485
- "contentHash": "93f7c41675e8f3868d1880542f7fd505b3f50ed9140411b08a0896223e2ae35c",
17485
+ "contentHash": "ec4cfc7906dbafd61eeadc04bc4d6212c2dd89e144e06c6291e9318a98f389d8",
17486
17486
  "sourceKind": "component_definition",
17487
17487
  "sourceId": "praxis-filter-form",
17488
17488
  "corpusVersion": "1.0.0"
@@ -0,0 +1,49 @@
1
+ # Optional action text: editor validation
2
+
3
+ Classification: `local-pequena`; fit: `ja-suportado-mal-nomeado-ou-mal-materializado`.
4
+ Owner: Dynamic Form actions editor. The existing FormActionButton and action
5
+ layout properties already represent optional text. Native text inputs bound
6
+ directly to absent values displayed the literal `undefined`.
7
+
8
+ The editor now projects nullish text as an empty input for default/custom action
9
+ labels, icons, shortcuts, tooltips, identifiers and CSS classes. This is a display
10
+ fallback, not configuration normalization: opening tabs emits no config change,
11
+ untouched optional properties remain absent, and host strings (including a literal
12
+ `undefined`) remain strings. Explicit editing and clearing keep the existing
13
+ configChange semantics. No CSS, token, translation, permission or execution rule
14
+ changed.
15
+
16
+ Validation:
17
+
18
+ - 11 focused ActionsEditorComponent tests passed, including DOM rendering across
19
+ all three tabs, no mutation on open, and editing/clearing without materializing
20
+ untouched optional properties. An initial test fixture omitted required
21
+ `visible`; the fixture was corrected before the successful run.
22
+ - Dynamic Form production build and git diff whitespace check passed.
23
+ - Internal browser at `http://localhost:4003/page-builder-ia`, dark desktop,
24
+ 1375 × 912: opened Actions → Custom buttons → added a temporary button → expanded
25
+ it. Icon, tooltip, shortcut and CSS class rendered empty. Editing tooltip was
26
+ reflected in the visual JSON document, with the other three properties absent.
27
+ Cancel/discard closed the temporary draft without Apply or Save.
28
+ - Selecting Ayla Hayes in the table loaded the matching presentation form.
29
+ - The existing browser tab subsequently stopped responding while switching
30
+ selection/mode, including to reload. That sequence is not counted as validated;
31
+ no causal connection to the text fallback was established.
32
+ - Recovery used a fresh internal tab on the same official route. At 1280 × 720
33
+ with editing off, Ayla loaded successfully, then selecting Jonah updated the
34
+ identity, contact and professional values to Jonah after the loading state.
35
+ The presentation remained read-only. The recovered tab was left open showing
36
+ the details. This confirms the fresh-session selection flow, not resolution of
37
+ the previous long-session responsiveness failure.
38
+ - Subsequent investigation identified and corrected a shared translation lookup
39
+ bottleneck, while reproducing an unresolved edit-exit transition; see the
40
+ [performance investigation](../../praxis-core/docs/i18n-editor-performance-2026-09-08.md).
41
+ - Read-only API comparison confirmed the saved page was identical to the baseline
42
+ before this turn. No employee data was written.
43
+
44
+ This cycle does not certify mobile, the full workspace, live AI flows or a new
45
+ persistence round-trip. The correction changes neither accepted paths nor public
46
+ types/manifests; public API, authoring manifest and existing custom-action E2E
47
+ coverage were reviewed. README guidance was updated. No registry, HTTP corpus or
48
+ landing artifact regeneration is needed. Existing skill guidance already requires
49
+ canonical value preservation and visual checks; no new skill contract was needed.
@@ -64,6 +64,14 @@ Essa regra evita perda silenciosa do contrato canonico de Entity Lookup durante
64
64
  - IDs de linha devem ser únicos dentro da seção e IDs de coluna devem ser únicos dentro da linha;
65
65
  - o estado `dirty` desses editores é reversível: restaurar o snapshot inicial deve desabilitar novamente Apply/Save.
66
66
 
67
+ ## Responsive column values
68
+
69
+ The canonical grid uses integer values: `span` 1..12, `offset` 0..11 and `order` -12..12 for `xs`, `sm`, `md`, `lg` and `xl`. A missing or null value inherits the preceding breakpoint; XS defaults are 12, 0 and 0 respectively. These ranges validate each property independently; they do not impose `span + offset <= 12`.
70
+
71
+ Column controls, authoring-document validation and layout/config validation share the same domains. JSON Apply revalidates the current text before loading or emitting it, even if an earlier draft was valid. Diagnostics identify the property and breakpoint path. The AI `layout.column.add` input declares `span` as an integer. Invalid drafts are not silently rewritten; the editor withholds its preview and numeric summaries until corrected.
72
+
73
+ Core runtime resolvers recover malformed input into supported CSS grid values without mutating the source document. This is defensive rendering, not approval to save that input. Visibility commands preserve geometry and style; hiding XS/SM also preserves the previously effective MD visibility so inheritance does not unexpectedly hide larger screens.
74
+
67
75
  ## Visual Blocks Inside Layout
68
76
 
69
77
  Blocos visuais dentro de seção, linha ou coluna devem seguir a decisão
@@ -120,3 +128,82 @@ Estilos permanecem em `contextSnapshot.presentation`, acessível pela aba **Esti
120
128
  - **Geral → Dados do formulário** separates **Criar / Editar / Visualizar** from **Automático / Campos / Apresentação**. Selecting presentation in Create/Edit keeps the operation unchanged and explains the inactive state with an explicit action to switch to View.
121
129
  - **Estilo da apresentação** remains discoverable regardless of the current mode. It previews sample data and does not activate presentation by itself. Filter Form does not expose this tab because it has no presentation runtime.
122
130
  - Applying or finishing widget editing updates the page draft. **Salvar página** persists the composition. Shortening sample text affects the preview only.
131
+
132
+
133
+ ### Page Builder: effective layout and authored input
134
+
135
+ The widget config editor receives the live `config` through the component editor's transient
136
+ `contextResolver`. Its sections and API field metadata are available for editing without turning
137
+ schema materialization into persisted page input. Opening, cancelling, or changing only mode or
138
+ presentation does not copy generated sections, schema hashes, hooks, or field metadata into the page.
139
+
140
+ An explicit section/row/column change projects the edited `sections` into authored `inputs.config`.
141
+ When the existing `layoutPolicy.source` is `schema`, this layout edit changes it to `authored`,
142
+ preserving the other policy settings. Reload reconciles current API metadata with the saved layout;
143
+ it does not store the selected record as an authoring snapshot. The intended contract preserves authored configuration and explicit property removals, storing
144
+ per-field overrides by canonical field name rather than the untouched API catalog. The
145
+ [corporate integrity review](../test-dev/corporate-integrity-review-2026-09-08.md)
146
+ recorded gaps in partial schemas, visual override materialization and automatic presentation.
147
+ Those gaps were corrected with the focused validation documented in
148
+ [the implementation evidence](../test-dev/corporate-integrity-fixes-2026-09-08.md).
149
+ The original browser demonstration with explicit presentation alone was not proof of these cases.
150
+
151
+ The Layout palette lists only eligible API fields that are not already positioned. An empty palette
152
+ with an allocated catalog says that all available fields are already in the layout; it does not imply
153
+ that the resource schema could not be loaded.
154
+
155
+
156
+ The wrapper also exposes the existing `configPersistenceStrategy` as **Fonte da configuração**.
157
+ **Definida nesta página** selects `input-first`; **Preferências salvas** selects `local-first`.
158
+ The runtime default remains `local-first`. When the goal is a page-owned layout, select `input-first`
159
+ so an older saved form preference does not replace the correctly persisted page sections on reload.
160
+ Changing only the source preserves the authored page config even if the currently displayed effective
161
+ layout came from older local preferences. This is an existing runtime input, not a new persistence
162
+ channel or authoring operation.
163
+
164
+
165
+ ### Governed field overrides and partial operation schemas
166
+
167
+ The effective editor catalog is a projection, not the complete authored document.
168
+ Editing a field must preserve authored overrides for fields absent from both the
169
+ current catalog and its initial baseline. A field present in the baseline and
170
+ explicitly deleted from the edited document may have its authored override removed.
171
+ Reintroducing a schema field into the layout remains a separate layout operation.
172
+
173
+ With `layoutPolicy.source='schema'`, permitted visual overrides (for example
174
+ `placeholder` and `width`) are reconciled before layout materialization through
175
+ Core's `applyLocalFormCustomizations`. They must not disappear on reload. This
176
+ uses the same server-ownership rules as authored layouts: server labels,
177
+ requiredness, visibility and field access cannot be overridden through a local
178
+ widget document. The existing `field.label.set` and `field.required.set` authoring
179
+ operations remain valid for locally owned fields; persisting those properties
180
+ is not evidence that a schema-governed runtime may supersede backend semantics.
181
+
182
+ Detaching geometry from schema ownership preserves the existing detail intent
183
+ and automatic presentation. Explicit `presentationModeGlobal=false` still asks
184
+ for readonly controls; edit/create still use input mode. No business operation,
185
+ submit endpoint or command policy is changed by moving a field.
186
+
187
+ Validation must follow editor output through JSON serialization and runtime schema
188
+ rehydration, in addition to checking the emitted document. The precedence matrix
189
+ also supplies an older conflicting preference through `AsyncConfigStorage` with
190
+ `layoutPolicy.persistence='authorable'`: `input-first` keeps the page layout and
191
+ visual override, while `local-first` uses the saved preference. Both cases reopen
192
+ the wrapper against the resulting runtime config and verify that a no-op save
193
+ preserves the authored page document instead of copying the effective preference.
194
+ Transient layouts skip that preference read and cannot prove this conflict case.
195
+
196
+
197
+ Integrity review validation (2026-09-08): 32 focal tests passed across the widget
198
+ config editor, schema layout policy, and external config hydration suites. The
199
+ reorder round-trip includes automatic detail presentation after the saved layout
200
+ becomes authored. The tests also preserve server readonly authority against a
201
+ conflicting canonical local value. Package builds and live browser validation are
202
+ tracked by the integration review; this focal run does not claim those gates.
203
+
204
+
205
+ Conflicting preference regression: the external config hydration suite passed all
206
+ 11 tests, including the two strategy cases with conflicting order, section title,
207
+ and placeholder (log `/private/tmp/praxis-form-preference-conflict-tests.log`). This
208
+ is an isolated storage-service test and serialized widget round-trip; actual
209
+ backend persistence and visual editor interaction are validated separately.