Skip to content

fix(hydra-gates): stop gates 54, 55 and 102 reporting non-defects - #898

Merged
rubenvdlinde merged 1 commit into
mainfrom
fix/manifest-gates-false-positives
Nov 3, 2026
Merged

rubenvdlinde merged 1 commit into
mainfrom
fix/manifest-gates-false-positives

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Three manifest gates report things that are not defects. This PR teaches each one the shape it was missing, narrowly, and keeps a deliberately bad case of the same shape failing.

Gate 102 (manifest strings need an nl.json key)

Visible-field keys (title, label, description, task, ...) also appear where the value is not copy. A value is now skipped only when both its place and its shape say it is not text:

where skipped only when the value is example
under columnWidths, width, minWidth, maxWidth, paneWidth a CSS length: number plus px, %, rem, em, fr, vw, ch, or auto dossiq "columnWidths": {"title": "275px"}
colorMap, variantMap, iconMap, typeMap (whole block: keys are data values, values are tokens per the schema) pipelinq "colorMap": {"task": "purple"}
cardLayout, expandableRows, a field-list row, a board's card, a fields entry with initialsPath a field path (title, owner.name) pipelinq "expandableRows": {"title": "title"}
anywhere a binding token with no space (@object.title, @me) pipelinq "props": {"title": "@object.title"}

This starts from the screens GATE-FIX patch (gate-102-checker.patch) and narrows it where it skipped real copy:

  • it skipped every value under columnWidths, now only CSS lengths;
  • it skipped every card block, which includes nav.card.title, an i18n key in the schema; now only a board's card;
  • it skipped any value under the field-path keys, now only field paths, so "cardLayout": {"title": "Case title"} is still copy;
  • it skipped any string starting with @, now only binding tokens, so "@ mention someone" is still copy.

Gate 55 (detail-page discipline)

config.band (schema 2.171, CnDetailPage bandWidgets()) places widgets in a row above the body. The rule-8 check now reads it like sideColumn: a string id or {widgetId} entry places a declared widget, an inline definition needs none. Still reported: a band widget that also has a layout cell, one also in the side column, one named twice, and a band entry naming no declared widget (CnDetailPage drops it silently).

Gate 54 (relation dialect)

A register.d fragment is deep-merged onto the base register (ADR-037, pipelinq ConfigFileLoaderService). A filter token @object.<field> is now resolved against the merged schema: the fragment's own properties plus that schema's properties in the base register and the other fragments. Mock and example registers are separate documents and are not merged, in either direction.

Verified

Fleet run of the three helpers, origin/main vs this branch, on the development tip of all 21 swept apps:

gate change everything else
102 dossiq FAIL 1 to PASS (275px); pipelinq FAIL 8 to PASS (@object.title, CheckCircleOutline, description, handle, ownerId, purple, title, value) portaliq keeps its 2 real findings (Indeling, Upload); 18 apps unchanged
55 pipelinq: 11 "maps to 0 layout cell(s)" findings gone, every one a config.band widget pipelinq's 12 remaining unplaced widgets (declared, placed nowhere) stay; all other apps byte-identical
54 pipelinq: the crmTask.contactMoment @object.clientId finding gone all other apps byte-identical

Strings the new gate 102 no longer collects, fleet-wide (all checked by hand to be field paths, tokens or lengths): dossiq 275px, title (board card, cardLayout); pipelinq the 8 above plus name (initialsPath entries); portaliq hostname, displayName (field-list row). No string was added.

After this, gate 102 on dossiq development reports no untranslated string.

Tests:

  • test_check_manifest_l10n_coverage.py: new cases for every skip, and a STILL_COPY manifest that puts real copy under each of those keys ("columnWidths": {"title": "Open cases"}, "275px" as a page title, nav.card.title, a worded cardLayout.title, "@ mention someone", "12 px wide"); all still reported. Six mutants of the new skip logic (drop the width guard, the field-path guard, the board-parent guard, the token grammar, the value-map skip, the width context) each fail the suite.
  • test_check_detail_page_placement.py: 7 band cases, 3 of them controls that must still fail. 21 tests OK.
  • test_check_relation_dialect.py: 5 fragment-merge cases, 3 controls (a field nobody declares, a mock register in both directions). 44 tests OK.
  • Every helper suite that touches these checkers is green: the three above plus test_check_detail_page_icon_registry.py, test_check_detail_page_cross_app.py, test_check_form_labels.py, test_gate_diff_provenance.sh, test_gate_numbers_unique.sh. The full run-helper-suites.sh passed 82 suites with no failure before my 25-minute local cap; the rest is left to CI's Package invariants.

Inherited, not from this PR: Package invariants hits its 30-minute timeout on every open PR here today (#888, #896, #897 and others' PRs), so it reads CANCELLED.

AI disclosure: prepared with Claude Code (Opus 5.5).

🤖 Generated with Claude Code

Gate 102 skips a visible-field value only when its place and shape both
say it is not copy: a CSS length under a width key, a value-map token, a
field path in a field-path block, or an @ binding token.
Gate 55 reads config.band as a widget placement, like sideColumn.
Gate 54 resolves @object.<field> filter tokens in a register.d fragment
against the schema merged with the base register and other fragments.

Assisted-by: ClaudeCode:claude-opus-5-5
@rubenvdlinde
rubenvdlinde merged commit 9e35872 into main Nov 3, 2026
48 of 49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant