@praxisui/dynamic-form 10.0.0-rc.36 → 10.0.0-rc.38

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
@@ -55,6 +55,12 @@ Use `optionSource.dependsOn` for dependent option lists and workflow actions for
55
55
 
56
56
  Use a local `FormConfig` when the host already knows the sections and fields.
57
57
 
58
+ With `configPersistenceStrategy="input-first"`, an explicitly bound host configuration remains authoritative even when it contains only actions or other policies. The schema for the current operation supplies missing fields and layout; stale persisted fields are not used to fill those gaps.
59
+
60
+ Each form owns its mutable `GenericCrudService` and editor field/rule context. Sibling forms cannot change one another's resource, custom endpoints or schema client. This is a breaking beta correction for hosts that previously replaced an ancestor `GenericCrudService`: configure the form through `resourcePath`, `apiEndpointKey`, `apiUrlEntry` and the direct-form `customEndpoints` input. An ancestor service subclass is no longer used by the form; HTTP interceptors, `API_URL` and shared infrastructure remain inherited. Tests that substitute the client must use `TestBed.overrideComponent(PraxisDynamicForm, { add: { providers: [{ provide: GenericCrudService, useValue: crudMock }] } })`, retaining the other component providers.
61
+
62
+ An explorer combining selectors from several resources is a local form, not an edit command for one of those resource DTOs. Its fields may query real API options through their own resource metadata while remaining `source: 'local'` with `submitPolicy: 'omit'`. Use a distinct form identity when replacing a schema-backed command with such an explorer; persisted connections are still restored for their original identity. The `/dependency-fields-demo` reference follows this pattern and gives the current host definition precedence with `configPersistenceStrategy="input-first"`; its previous `cascade-*` configurations and connections are left untouched.
63
+
58
64
  ```ts
59
65
  import { Component } from '@angular/core';
60
66
  import { FormConfig } from '@praxisui/core';
@@ -747,3 +753,7 @@ suportada, ocupa a linha seguinte. Nenhum documento ou protocolo de Save é alte
747
753
  - [Canonical technical overview: Overview](https://praxisui.dev/docs/components/praxis-dynamic-form)
748
754
  - [Praxis Angular public catalog](https://praxisui.dev/angular)
749
755
  <!-- praxis-npm-catalog-links:end -->
756
+
757
+ ### Filhos de páginas governadas
758
+
759
+ Consulte [o adapter nativo de página](docs/governed-page-widget-adapter.md) para reconstrução sem defaults, presença exata, identidade derivada e execução sem preferências concorrentes.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-21T13:45:30.091Z",
3
+ "generatedAt": "2026-10-23T20:24:09.136Z",
4
4
  "packageName": "@praxisui/dynamic-form",
5
- "packageVersion": "10.0.0-rc.36",
5
+ "packageVersion": "10.0.0-rc.38",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -49,7 +49,7 @@
49
49
  },
50
50
  {
51
51
  "name": "mode",
52
- "type": "'create' | 'edit' | 'view'",
52
+ "type": "'create' | 'edit' | 'view' | 'presentation' | 'dossier'",
53
53
  "required": false,
54
54
  "description": "Modo do formulario",
55
55
  "label": "Modo",
@@ -176,9 +176,9 @@
176
176
  },
177
177
  {
178
178
  "name": "configPersistenceStrategy",
179
- "type": "'local-first' | 'input-first'",
179
+ "type": "'local-first' | 'input-first' | 'volatile'",
180
180
  "required": false,
181
- "description": "Define se a configuracao local persistida ou os inputs do host tem precedencia; input-first preserva inclusive o mode explicito contra preferencias persistidas.",
181
+ "description": "Define se a configuracao local persistida ou os inputs do host tem precedencia; input-first preserva inclusive o mode explícito; volatile usa a configuração do host sem ler, salvar ou limpar preferências do filho.",
182
182
  "default": "local-first"
183
183
  },
184
184
  {
@@ -6865,9 +6865,11 @@
6865
6865
  "allowedValues": [
6866
6866
  "create",
6867
6867
  "edit",
6868
- "view"
6868
+ "view",
6869
+ "presentation",
6870
+ "dossier"
6869
6871
  ],
6870
- "description": "Modo de operação"
6872
+ "description": "Modos nativos preservados em documentos. Em novos fluxos, prefira view com presentationModeGlobal para separar operação dos dados e apresentação."
6871
6873
  },
6872
6874
  {
6873
6875
  "name": "presentation",
@@ -6884,9 +6886,10 @@
6884
6886
  "type": "string",
6885
6887
  "allowedValues": [
6886
6888
  "local-first",
6887
- "input-first"
6889
+ "input-first",
6890
+ "volatile"
6888
6891
  ],
6889
- "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."
6892
+ "description": "Precedência entre configuração persistida e contrato explícito do host. Use volatile para filhos controlados por página, sem storage independente. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor."
6890
6893
  },
6891
6894
  {
6892
6895
  "name": "generatedLayoutPreset",
@@ -9415,9 +9418,9 @@
9415
9418
  {
9416
9419
  "chunkIndex": 0,
9417
9420
  "chunkKind": "summary",
9418
- "content": "Component ID: praxis-dynamic-form\nSelector: praxis-dynamic-form\nFriendly Name: Praxis Dynamic Form\nDescription: Formulario dinamico com layout por secoes/linhas/colunas e campos renderizados por metadados.\nCategory: form\nLib/Package: @praxisui/dynamic-form\nTags: widget, form, configurable, hasWizard, stable\nInputs:\n - resourcePath (string)\n - resourceId (string | number | null)\n - initialValue (Record<string, unknown> | null)\n - emptyState (PraxisDynamicFormEmptyState | null)\n - editorialContext (Record<string, unknown> | null)\n - mode ('create' | 'edit' | 'view')\n - config (FormConfig)\n - actions (FormConfig['actions'] | null)\n - schemaSource ('resource' | 'filter')\n - schemaUrl (string | null)\n - readUrl (string | null)\n - apiEndpointKey (ApiEndpoint | string | null)\n - apiUrlEntry (ApiUrlEntry | null)\n - submitUrl (string | null)\n - submitMethod ('post' | 'put' | 'patch' | null)\n - submitIdempotencyKey (string | null)\n - submitCorrelationId (string | null)\n - submitResourceVersion (string | number | null)\n - submitResourceVersionTargetResourceKey (string | null)\n - submitResourceVersionTargetIdField (string | null)\n - responseSchemaUrl (string | null)\n - enableCustomization (boolean)\n - showAiAssistant (boolean)\n - formId (string)\n - componentInstanceId (string)\n - configPersistenceStrategy ('local-first' | 'input-first')\n - layout (FormLayout)\n - generatedLayoutPreset ('default' | 'compactPresentation')\n - layoutPolicy (DynamicFormLayoutPolicy | null)\n - backConfig (BackConfig)\n - hooks (FormHooksLayout)\n - removeEmptyContainersOnSave (boolean)\n - reactiveValidation (boolean | null)\n - reactiveValidationDebounceMs (number | null)\n - notifyIfOutdated ('inline' | 'snackbar' | 'both' | 'none')\n - snoozeMs (number)\n - autoOpenSettingsOnOutdated (boolean)\n - readonlyModeGlobal (boolean | null)\n - disabledModeGlobal (boolean | null)\n - presentation (DynamicFormPresentationSnapshot | null)\n - presentationPreset (FormPresentationPreset)\n - presentationModeGlobal (boolean | null)\n - fieldIconPolicy ('all' | 'presentation-only' | 'none')\n - visibleGlobal (boolean | null)\n - customEndpoints (EndpointConfig)\nOutputs:\n - formSubmit (FormSubmitEvent)\n - formCancel (void)\n - formReset (void)\n - configChange (FormConfig)\n - configPatchChange (DynamicFormConfigPatchChangeEvent)\n - formReady (FormReadyEvent)\n - valueChange (FormValueChangeEvent)\n - payloadPreviewChange (FormPayloadPreviewEvent)\n - syncCompleted (SyncResult)\n - initializationError (FormInitializationError)\n - enableCustomizationChange (boolean)\n - customAction (FormCustomActionEvent)\n - actionConfirmation (FormActionConfirmationEvent)\n - schemaStatusChange ({ outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string })\n - reactiveDeterminationExecuted (ReactiveDeterminationExecutionEvent)\n - reactiveDeterminationPendingChange (boolean)\n",
9421
+ "content": "Component ID: praxis-dynamic-form\nSelector: praxis-dynamic-form\nFriendly Name: Praxis Dynamic Form\nDescription: Formulario dinamico com layout por secoes/linhas/colunas e campos renderizados por metadados.\nCategory: form\nLib/Package: @praxisui/dynamic-form\nTags: widget, form, configurable, hasWizard, stable\nInputs:\n - resourcePath (string)\n - resourceId (string | number | null)\n - initialValue (Record<string, unknown> | null)\n - emptyState (PraxisDynamicFormEmptyState | null)\n - editorialContext (Record<string, unknown> | null)\n - mode ('create' | 'edit' | 'view' | 'presentation' | 'dossier')\n - config (FormConfig)\n - actions (FormConfig['actions'] | null)\n - schemaSource ('resource' | 'filter')\n - schemaUrl (string | null)\n - readUrl (string | null)\n - apiEndpointKey (ApiEndpoint | string | null)\n - apiUrlEntry (ApiUrlEntry | null)\n - submitUrl (string | null)\n - submitMethod ('post' | 'put' | 'patch' | null)\n - submitIdempotencyKey (string | null)\n - submitCorrelationId (string | null)\n - submitResourceVersion (string | number | null)\n - submitResourceVersionTargetResourceKey (string | null)\n - submitResourceVersionTargetIdField (string | null)\n - responseSchemaUrl (string | null)\n - enableCustomization (boolean)\n - showAiAssistant (boolean)\n - formId (string)\n - componentInstanceId (string)\n - configPersistenceStrategy ('local-first' | 'input-first' | 'volatile')\n - layout (FormLayout)\n - generatedLayoutPreset ('default' | 'compactPresentation')\n - layoutPolicy (DynamicFormLayoutPolicy | null)\n - backConfig (BackConfig)\n - hooks (FormHooksLayout)\n - removeEmptyContainersOnSave (boolean)\n - reactiveValidation (boolean | null)\n - reactiveValidationDebounceMs (number | null)\n - notifyIfOutdated ('inline' | 'snackbar' | 'both' | 'none')\n - snoozeMs (number)\n - autoOpenSettingsOnOutdated (boolean)\n - readonlyModeGlobal (boolean | null)\n - disabledModeGlobal (boolean | null)\n - presentation (DynamicFormPresentationSnapshot | null)\n - presentationPreset (FormPresentationPreset)\n - presentationModeGlobal (boolean | null)\n - fieldIconPolicy ('all' | 'presentation-only' | 'none')\n - visibleGlobal (boolean | null)\n - customEndpoints (EndpointConfig)\nOutputs:\n - formSubmit (FormSubmitEvent)\n - formCancel (void)\n - formReset (void)\n - configChange (FormConfig)\n - configPatchChange (DynamicFormConfigPatchChangeEvent)\n - formReady (FormReadyEvent)\n - valueChange (FormValueChangeEvent)\n - payloadPreviewChange (FormPayloadPreviewEvent)\n - syncCompleted (SyncResult)\n - initializationError (FormInitializationError)\n - enableCustomizationChange (boolean)\n - customAction (FormCustomActionEvent)\n - actionConfirmation (FormActionConfirmationEvent)\n - schemaStatusChange ({ outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string })\n - reactiveDeterminationExecuted (ReactiveDeterminationExecutionEvent)\n - reactiveDeterminationPendingChange (boolean)\n",
9419
9422
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.metadata.ts",
9420
- "contentHash": "8425658a28ef61e2ebcf2ce2cc5b45835050556a4f810e83a4c167290dfcd80a",
9423
+ "contentHash": "c23522b0ae4de2b4f759620ac16675455e6d0fe9e97b630e7248b82a8a3d463c",
9421
9424
  "sourceKind": "component_definition",
9422
9425
  "sourceId": "praxis-dynamic-form",
9423
9426
  "corpusVersion": "1.0.0"
@@ -9845,9 +9848,9 @@
9845
9848
  {
9846
9849
  "chunkIndex": 43,
9847
9850
  "chunkKind": "authoring_manifest",
9848
- "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\"}]}",
9851
+ "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\",\"presentation\",\"dossier\"],\"description\":\"Modos nativos preservados em documentos. Em novos fluxos, prefira view com presentationModeGlobal para separar operação dos dados e apresentaçã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\",\"volatile\"],\"description\":\"Precedência entre configuração persistida e contrato explícito do host. Use volatile para filhos controlados por página, sem storage independente. 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\"}]}",
9849
9852
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-dynamic-form-authoring-manifest.ts",
9850
- "contentHash": "71de795e514367583af30f004099e53c0376010d58718a6b73935e544a090303",
9853
+ "contentHash": "2c3f132524d3cf73b6c9cb6f4591d2b1c076e1b444aa5c792be33a8d3d758c46",
9851
9854
  "sourceKind": "component_definition",
9852
9855
  "sourceId": "praxis-dynamic-form",
9853
9856
  "corpusVersion": "1.0.0"
@@ -16537,9 +16540,11 @@
16537
16540
  "allowedValues": [
16538
16541
  "create",
16539
16542
  "edit",
16540
- "view"
16543
+ "view",
16544
+ "presentation",
16545
+ "dossier"
16541
16546
  ],
16542
- "description": "Modo de operação"
16547
+ "description": "Modos nativos preservados em documentos. Em novos fluxos, prefira view com presentationModeGlobal para separar operação dos dados e apresentação."
16543
16548
  }
16544
16549
  ],
16545
16550
  "editableTargets": [
@@ -17907,9 +17912,9 @@
17907
17912
  {
17908
17913
  "chunkIndex": 30,
17909
17914
  "chunkKind": "authoring_manifest",
17910
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"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\":\"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\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\"],\"description\":\"Modo de operação\"}]}",
17915
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"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\":\"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\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\",\"presentation\",\"dossier\"],\"description\":\"Modos nativos preservados em documentos. Em novos fluxos, prefira view com presentationModeGlobal para separar operação dos dados e apresentação.\"}]}",
17911
17916
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-filter-form-authoring-manifest.ts",
17912
- "contentHash": "e87e0eebe5c750ff0bf9624b953e5ad603ae63ca2584702c9618500202fbed00",
17917
+ "contentHash": "87565432bc9d9f832bcd7f5d85001fe6d2eca9009c4f211468588e358ef89239",
17913
17918
  "sourceKind": "component_definition",
17914
17919
  "sourceId": "praxis-filter-form",
17915
17920
  "corpusVersion": "1.0.0"
@@ -4,7 +4,7 @@ doc_type: "adr"
4
4
  component: "praxis-dynamic-form"
5
5
  status: "accepted"
6
6
  owner: "praxis-ui"
7
- last_updated: "2026-09-10"
7
+ last_updated: "2026-10-23"
8
8
  ---
9
9
 
10
10
  # Dynamic Form Authoring Document Semantics
@@ -23,6 +23,26 @@ Ao aplicar um documento canônico:
23
23
 
24
24
  Payloads legados ou parciais recebidos por APIs de compatibilidade, como `applyConfigFromAdapter(...)`, permanecem com semântica `merge-compat`: campos não informados devem ser preservados até migração completa para o contrato canônico.
25
25
 
26
+ ## Rule conversion and recovery
27
+
28
+ `config.formRules` owns the canonical rule expression and both effect branches.
29
+ `formRulesState` is derived visual authoring state. Wizard inline JSON Logic must
30
+ survive Apply, Save and reopen unchanged. Conditions outside the visual graph
31
+ vocabulary remain intact inline and are diagnosed as `runtime-only`; a valid
32
+ root-data reference (`var: ''`) is not an invalid field reference.
33
+
34
+ A partial graph must never weaken an AND/OR expression by dropping children.
35
+ Missing rule roots, rules without a serializable target, and missing, cyclic or
36
+ unsupported explicit condition graph nodes block Apply/Save while
37
+ retaining the draft and last accepted configuration. Repairing through the
38
+ properties panel revalidates the draft. Deleting the last rule removes both
39
+ `formRules` and `formRulesState`, including after a validation failure.
40
+
41
+ Editor validation that gates Apply/Save uses the injected `PraxisJsonLogicService`
42
+ and the same host operator registry as runtime evaluation. A registered host
43
+ operator can remain runtime-only in the visual builder and must still save and
44
+ reopen. Unknown operators and invalid arity remain blocked.
45
+
26
46
  ## Filter Form projection
27
47
 
28
48
  `praxis-filter-form` compartilha o mesmo documento canônico, parser e serializer,
@@ -161,7 +181,8 @@ that the resource schema could not be loaded.
161
181
 
162
182
  The wrapper also exposes the existing `configPersistenceStrategy` as **Fonte da configuração**.
163
183
  **Definida nesta página** selects `input-first`; **Preferências salvas** selects `local-first`.
164
- The runtime default remains `local-first`. When the goal is a page-owned layout, select `input-first`
184
+ **Configuração temporária** selects `volatile`, which never reads, saves or clears independent child preferences.
185
+ The runtime default remains `local-first`. For ordinary page layouts, select `input-first`
165
186
  so an older saved form preference does not replace the correctly persisted page sections on reload.
166
187
  Changing only the source preserves the authored page config even if the currently displayed effective
167
188
  layout came from older local preferences. This is an existing runtime input, not a new persistence
@@ -213,3 +234,11 @@ Conflicting preference regression: the external config hydration suite passed al
213
234
  and placeholder (log `/private/tmp/praxis-form-preference-conflict-tests.log`). This
214
235
  is an isolated storage-service test and serialized widget round-trip; actual
215
236
  backend persistence and visual editor interaction are validated separately.
237
+
238
+ ## Governed page child adapter
239
+
240
+ For published page authorship, use [the native page adapter](governed-page-widget-adapter.md), not the
241
+ common wrapper output directly. It preserves exact presence and only explicit editor deltas, locks
242
+ bindings/context to the admitted seed, and derives volatile execution inputs from page/widget identity.
243
+ Native `presentation` and `dossier` modes survive open/save/reopen; new visual flows still prefer
244
+ `view` with a separate display preference. Filter Form keeps its three-mode runtime subset.
@@ -0,0 +1,134 @@
1
+ # P1 form authoring — issues #631, #632 and #633
2
+
3
+ Classification: public behavior change with cross-library consumers. Canonical owners are Dynamic Form (rules bridge, form client/context and hydration) and Metadata Editor (cascade authoring). No exported type, endpoint, workspace configuration or dependency change.
4
+
5
+ ## Scope and compatibility
6
+
7
+ - Preserve wizard JSON Logic and both property branches through Apply/Save/reopen. Invalid graphs remain available for repair and cannot silently become unconditional rules.
8
+ - Preserve non-identity cascade filter maps and extraction paths. Table rows own the current edit draft; suggestions fill missing mappings.
9
+ - Give each mounted form its own mutable CRUD client and editor context. This is a breaking beta DI correction; ancestor GenericCrudService replacements must migrate to supported component inputs or component-level test overrides. Shared HTTP infrastructure remains inherited.
10
+ - Make the Quickstart dependency demo a local relationship explorer. Selectors query real resources individually; fields are omitted from domain payloads. Its new document identities avoid inheriting old schema-backed connections.
11
+ - Open field customization from the current canonical materialization, rather than stale selection/render snapshots.
12
+
13
+ Existing contracts cover these behaviors: already supported but incorrectly materialized. No parallel contract or new authoring vocabulary was introduced.
14
+
15
+ ## Review and gate resolution
16
+
17
+ The implementation was isolated on main 8da9401a8; unrelated dirty checkout changes and unrelated documentation hunks were excluded. Reviewers different from the authors inspected conversion/diagnostics, cascade editing, DI ownership, demo and both remaining gates.
18
+
19
+ The old label test conflated a selected snapshot with the current materialization. Regression tests now preserve the Cargo expectation while giving the canonical document/presentation that label, and making selection/cache explicitly obsolete.
20
+
21
+ The earlier host-test compilation failure involved a nullable assertion in an unrelated dirty test. That test is absent from this main baseline; the demo target is compiled and executed without importing the unrelated changes or altering TypeScript configuration.
22
+
23
+ Additional review covered deleting the last invalid rule, repairing through the properties panel, diagnostics for conditions outside the graph subset and loading rules without formRulesState. Valid runtime-only conditions must remain intact; invalid conditions must remain blocked. JSON Logic var:'' is a valid root-data reference, not an invalid field path.
24
+
25
+ ## Validation
26
+
27
+ All selected gates passed on the isolated source tree:
28
+
29
+ | Gate | Result |
30
+ | --- | --- |
31
+ | Rule converters, configuration editor, diagnostics and isolation | 114 passed |
32
+ | Dynamic Form main/config/editorial/presentation/manifest/hydration/protocol | 334 passed |
33
+ | Cascade service and tab | 17 passed |
34
+ | CRUD dialog host consumer | 50 passed |
35
+ | Additional DI consumers: entity selection, schema recovery, layout tabs, presentation preset and widget editor | 77 passed |
36
+ | Dependency demo host target | 1 passed |
37
+ | Official build helper: Metadata Editor, Dynamic Form, CRUD + dependency closure | Passed |
38
+ | Final Dynamic Form and CRUD builds after gate repairs | Passed |
39
+ | Published documentation assets | Passed, 5 packages |
40
+ | MatSelect content model and diff whitespace | Passed |
41
+
42
+ The isolated dependency tree was installed using npm ci. No broad full-test-suite
43
+ or release certification is claimed. Counts represent separate lanes, not a
44
+ claim about unique test coverage.
45
+
46
+ Exact focal spec includes and commands are reproducible from the changed spec
47
+ paths; the main lane also includes first/external hydration, authoring protocol
48
+ and the authoring manifest. Builds use development configuration. Artifact logs
49
+ are retained in the workspace under artifacts/form-p1-fixes-20261022/clean-*.log.
50
+
51
+ ## Final local browser smoke
52
+
53
+ The isolated checkout was served frozen on official UI4003, with its proxy
54
+ explicitly directed to unavailable local API8088. This smoke exercised the local
55
+ editor only and did not attempt option loading or domain submission.
56
+
57
+ Through the visible JSON tab of dependency-fields-demo, a malformed condition
58
+ (`{"===": []}`) produced an invalid-condition diagnostic and disabled Apply and
59
+ Save. Correcting the document by removing rule/state through the same JSON tab
60
+ re-enabled both buttons. Drafts were cancelled and tabs closed; nothing was
61
+ saved to the host or remote configuration.
62
+
63
+ ![Invalid condition blocks Apply and Save](final-invalid-blocked.png)
64
+
65
+ ![Corrected document re-enables Apply and Save](final-recovered-enabled.png)
66
+
67
+ The native confirmation for the visual Remove button could not be accepted by
68
+ the browser-control adapter because its focus command timed out. That attempt
69
+ was abandoned and its tab closed. Visual deletion via that button is not claimed
70
+ as passed; the component regression covers deletion and reopen. The rule list
71
+ also retained a stale row after JSON replacement while canonical diagnostics
72
+ were empty: the remaining UI coherence work belongs to #635. The screenshots
73
+ record this limit rather than hiding it.
74
+
75
+ Tests are unit/component tests using ChromeHeadless, without a database. Dependency builds use the official build-libs helper and its dependency closure. No release workflow, deployment or domain mutation is performed.
76
+
77
+ ## Earlier visual audit evidence
78
+
79
+ The analyst journeys were repeated in Chrome on the previous shared source snapshot, using official UI4003/API8088 and assigned remote Neon branches with runtime identities/TLS. Those screenshots are historical visual evidence, not proof of this isolated revision. Current revision validation is listed separately above.
80
+
81
+ - #631: wizard Ativo=true/false controlled Foto visibility and required state; persisted expression and both effects survived reload.
82
+ - #632: Cargo/Departamento non-identity mapping survived explicit Edit, Save, Apply and reload.
83
+ - #633: RH, Base/Equipe/Membro and Ameaça/Missão/Incidente/Indenização chains completed with real filtered option requests; parent replacement/clear emptied descendants; no-result search and sibling-tab independence were checked.
84
+ - CRUD native Add dialog loaded its command schema and was closed without submission.
85
+
86
+ Limits retained: Foto originally arrived formHidden and required temporary exposure in the visible JSON editor. After reload the target catalog again omitted it, a remaining #635 issue. Structural dotted mapping proof does not certify backend acceptance of that filter. No narrow-screen, screen-reader, adverse-latency, remote ETag/concurrency or latest-release certification is claimed.
87
+
88
+ Detailed original audit artifacts are retained in the workspace artifacts/form-p1-fixes-20261022 directory and linked from the issue discussions. No credentials/network headers are published.
89
+
90
+ ## Derived artifacts and skills
91
+
92
+ README/JSON API owner documentation explains DI migration and the explorer; Metadata Editor README explains lossless cascade editing. No public-api, AI operation/path, manifest shape, HTTP corpus or landing-page contract changed, so no parallel derived contract was created. Authoring manifest tests and published documentation asset checks cover the existing surfaces.
93
+
94
+ Canonical cascade and runtime DI skill updates were previously integrated through praxis-codex-skills#826 and #827 and selectively synchronized. Existing form roundtrip guidance remains adequate: formRulesState is derived, canonical rules are preserved, and runtime discovery does not own persisted semantics. The additional gate repairs enforce that existing guidance.
95
+
96
+ ## Final review before integration — 2026-10-23
97
+
98
+ A new independent review of cad84dd00 found and corrected three cases before
99
+ integration:
100
+
101
+ - A missing or targetless rule root was silently dropped, so the new empty-rule
102
+ branch could delete the last accepted rules. Projection now rejects every
103
+ referenced invalid root, including a mixed valid/invalid graph. The editor
104
+ keeps the accepted document and invalid draft and blocks saving; an explicit
105
+ rootNodes=[] still supports intentional deletion.
106
+ - Blocking diagnostics used a built-in-only JSON Logic instance and rejected a
107
+ valid host operator. Editor diagnostics and command validation now share the
108
+ injected runtime service. A real registered operator is tested through runtime
109
+ evaluation and editor Save/reopen; unknown operators and invalid arity fail.
110
+ - Removing a cascade dependency retained its extraction override record. The
111
+ save path now removes both mapping and extraction override for removed
112
+ dependencies; save/reopen/re-add and last-dependency/default cases are covered.
113
+
114
+ An additional consumer inventory found four test fixtures still providing the
115
+ CRUD mock in the ancestor injector. They now use the documented component-level
116
+ replacement. The entity-selection fixture also supplies the current HttpResponse
117
+ read API while preserving request, error and cancellation assertions. The widget
118
+ editor fixture does not mount Dynamic Form and was intentionally left unchanged.
119
+
120
+ Before/after evidence: missing-root regressions failed before the fix; the host
121
+ operator regression failed before registry propagation; the extra DI lane had
122
+ 19 failures before fixture updates and finished 77/77. Final focused rules lane
123
+ 114/114 and cascades 17/17 passed. The 334-test form lane, 50-test CRUD lane and demo lane were also rerun after
124
+ the production repairs and passed. All three owner/consumer builds were rerun after production repairs.
125
+ No database or remote release workflow was required for these review repairs.
126
+
127
+ The earlier native-dialog/browser and #635 limitations remain unchanged. They
128
+ are not presented as newly validated by these unit/component regressions.
129
+
130
+ The two narrowly scoped guidance additions were independently reviewed and
131
+ integrated through praxis-codex-skills#829 (merge fb0fb5c). Both affected skills
132
+ were selectively synchronized and audited; the other 787 installed skill files
133
+ remained byte-identical and seven unrelated drifts were preserved. No new skill
134
+ or public contract was introduced.
@@ -0,0 +1,58 @@
1
+ # Dynamic Form em páginas governadas
2
+
3
+ O adapter do owner mantém `definition.inputs.config` como a única fonte de configuração do filho.
4
+ A página guarda autoria; o documento nativo é reconstruído a partir desses inputs. A projeção de
5
+ execução é transitória e nunca deve ser gravada de volta no documento da página.
6
+
7
+ O perfil inicial vem do contrato P0 `page-publication-p0` de `praxis-config-starter` (PR #506).
8
+ Core valida estrutura, referências, limites e exige validators dos owners. Este adapter valida o
9
+ perfil nativo local; não autoriza uma fonte, registra uma seed ou substitui a admissão no servidor.
10
+
11
+ `decodeDynamicFormPageInputs` reconstrói `praxis.dynamic-form.editor` v1:
12
+ config, bindings presentes (`mode`, `emptyState`, `presentationModeGlobal`) e contexto presente
13
+ (`backConfig`, `presentation`, `schemaPrefs`). Schema prefs só existe se algum dos três inputs
14
+ `notifyIfOutdated`, `snoozeMs`, `autoOpenSettingsOnOutdated` estiver presente. Ausência, `false`,
15
+ zero, objeto vazio admitido e `null` são preservados. Null em objetos mesclados de config é negado;
16
+ null dentro de arrays atômicos permanece autoria. `layoutScope` não cabe neste perfil.
17
+
18
+ Os cinco modos nativos são `create`, `edit`, `view`, `presentation` e `dossier`. O editor visual
19
+ continua preferindo os três modos de operação com `presentationModeGlobal` separado. Abrir um
20
+ documento nativo dos demais modos não deve convertê-lo. Filter Form mantém somente seus três modos.
21
+
22
+ `encodeDynamicFormPageInputs` é a projeção inversa sem defaults. Campos fora do perfil,
23
+ blocos vazios sem representação nos inputs, identidade/storage e dados de execução recebem
24
+ diagnóstico. O adapter não filtra silenciosamente autoria incompatível.
25
+
26
+ `projectDynamicFormPageEditorChanges(authoredInputs, editorBaseline, editorValue)` aplica apenas
27
+ deltas explícitos sobre a autoria original usando o reconciliador nativo do owner. Capture o
28
+ baseline após a normalização/montagem do editor e preserve-o durante aquela sessão. Alterar
29
+ bindings ou contexto do mesmo widget retorna `seed.replacement-required`; a página precisa
30
+ substituir o widget com nova key e nova fonte admitida. A API de projeção altera somente o draft
31
+ que o chamador recebe; ela não salva preferências nem persiste a página.
32
+
33
+ `materializeDynamicFormPageRuntimeInputs(inputs, pageId, widgetKey)` usa o helper canônico Core para
34
+ identidades `page:<pageId>:widget:<widgetKey>`, projeta `configPersistenceStrategy: 'volatile'`
35
+ e desabilita customização/copiloto independentes no filho. Submit e dados continuam nos contratos
36
+ de domínio existentes. Não existe input runtime `authoringDocument`.
37
+
38
+ A estratégia `volatile` impede leitura, gravação e limpeza de preferências próprias e conexão
39
+ persistida. O Form preserva identidade operacional para montar o formulário, mas as trilhas de
40
+ config/bindings/contexto/schema preferences ficam sem I/O de storage.
41
+ Defaults visuais/materializações transitórias permanecem internos ao runtime e ao editor.
42
+
43
+ Limites: JSON lossless, 256 KiB UTF-8 e profundidade 64 pelo helper Core compartilhado; o documento
44
+ integral da página também tem o mesmo orçamento. Não há host publicado, endpoint de publicação,
45
+ fonte admitida, banco ou release novos neste incremento. A integração Page Builder/host governado
46
+ é trabalho posterior; os wrappers comuns continuam atendendo os fluxos não governados existentes.
47
+
48
+ `volatile` também exclui overlays pessoais de configuração global nos defaults/estado de autoria
49
+ que o owner consome. A instância compartilhada `GlobalConfigService` pode ler sua chave global;
50
+ isso não é prova de zero leitura na aplicação. Tenant, cache, locale e CSP continuam infraestrutura
51
+ do host. O gate comprova ausência de I/O nas chaves do filho e ausência de influência da autoria
52
+ pessoal sobre a configuração publicada. Em Table, `TableDefaultsProvider.getDefaults(id,
53
+ { includeGlobal: false })` preserva defaults nativos sem duplicá-los; mudanças globais e reset
54
+ seguem a mesma política, inclusive o fallback de timezone usado em regras JSON Logic.
55
+
56
+ Respostas e filas de preferências capturam a geração, a identidade e a estratégia do filho. Trocar identidade, documento ou estratégia (inclusive A → volatile → A), ou destruir a instância, invalida a continuação antiga antes do próximo I/O ou da materialização. Uma requisição já enviada não é cancelada retroativamente. Respostas tardias de erro também passam pelo mesmo fence.
57
+
58
+ O fence segue a chave do recurso: conexão, inputs e schema preferences usam identidade do owner e geração do host; apresentação acrescenta a chave `form-pres:<id>:<mode>`. Hidratar mode/path das próprias preferências iniciais não troca o owner. Eventos de inputs do host invalidam a geração e iniciam uma resolução atual. Schema, config e escritas também capturam os bindings de runtime.