feat(apollo-wind): shared guardrail definitions layer with a canonical copy table [AL-574] - #1132
Open
andreizdrali-uipath wants to merge 1 commit into
Conversation
…l copy table Guardrail definitions were parsed, and their display copy hand-maintained, separately in Agents and Flow. The backend cannot supply built-in display copy: the DTO marks the validator friendly name [JsonIgnore] and never sets displayName, description or optionLabels for any built-in, so each frontend has described the same catalog itself. The two tables had drifted in 16 strings. Four modules own it once: - definitions-wire.ts hand-written public wire types, no zod - definitions-parse.ts private zod schemas, the only zod importer - definitions-copy.ts canonical English plus the copy-key contract - definitions-enrich.ts display-ready output for the shipped components No fetching. Host transport is irreducibly different (query library, HTTP client, tenant id vs name in the URL, and one host that never fetches because definitions arrive over postMessage), so definitions arrive as data, mirroring how the components already take their values. This matches PR #1107, which ships no transport either. parseGuardrailDefinitions never throws: guardrail surfaces render in shadow roots with no error boundary, where a thrown parse error blanks the panel. It returns valid definitions plus one entry per dropped definition. Unknown keys are stripped, not rejected, so a backend field addition cannot empty the catalog. EnrichedGuardrailDefinition extends GuardrailDefinition, so the result feeds GuardrailBuilder unchanged while carrying the fields hosts read outside the form. zod stays private and out of the published type surface, since hosts sit on different zod majors. Enforced by a compile-time bidirectional assignability assertion, a runtime key-set assertion, a single-export assertion, and a source-level import guard. The emitted declarations carry no zod reference. Copy keys are guardrail/<validator>/<slot>, slash-separated: one host's catalog is flat and its i18n library splits on '.', so a dotted key would miss and fall back to English while every other locale went quietly untranslated. EXPECTED_DIVERGENCES records all 16 copy decisions with reasons, asserted in both directions against each host's transcribed English so the table cannot rot.
Contributor
Dependency License Review
License distribution
Excluded packages
|
andreizdrali-uipath
marked this pull request as ready for review
September 8, 2026 14:28
apetraru-uipath
approved these changes
Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AL-574a: shared guardrail definitions layer
AL-574 under epic AL-526. Stacked on #1107 — draft until that merges.
Why
The backend never sends display copy for built-in guardrails (
DisplayName/Description/OptionLabelsare unset; the friendly name is[JsonIgnore]). So Agents and Flow each hand-maintain their own ~450-line copy table for the same 6 validators — and they've already drifted in 16 strings ("Detection threshold" vs "thresholds",SelfHarmvs "Self-harm", etc.). This ships that table once, plus the parsing it needs.What
definitions-wire.tsdefinitions-parse.tsparseGuardrailDefinitions. Only zod importer.definitions-copy.tsdefinitions-enrich.tsenrichGuardrailDefinitions→EnrichedGuardrailDefinition extends GuardrailDefinition.No fetching (mirrors #1107 — zero transport in its diff; each host's transport is irreducibly different). No component changed —
GuardrailBuilderalready takesdefinition: GuardrailDefinition;enriched[i]slots in with no cast.Worth a look
grep -rn zod dist/**/*.d.tsis empty for this folder.optionLabelsmerge. BYO definitions get zero curated copy.prompt_injection's description keeps Agents' wording (drops the "Noma Security" attribution otherwise); 11 more copy strings converge — full list + reasons in__fixtures__/host-copy-baselines.ts.guardrail/<validator>/<slot>(/, never.— one host's i18n catalog is flat and splits on., so a dotted key would silently fall back to English forever).Testing
351 tests (133 new), 100% lines/functions/statements on all 4 new modules. Golden fixtures instead of snapshots (repo has none; biome reformats file snapshots and fails them).
typecheck/lint/buildgreen.Gaps
wire-raw-capture.ts— fixtures are hand-derived from the backend C# source instead, cross-checked againstGuardrailsControllerTests.cs.main-based PR (same as feat(apollo-wind): guardrails component family (validator form + builder screen) #1107).forms/validation-converter.tsalso leaks a zod type into published types — flagged as a follow-up, not fixed here.Not in this PR: translating the copy into other locales (stays host-side, by design), any change to #1107's components, host adoption in Agents/Flow (separate tickets).
🤖 Generated with Claude Code