Skip to content

feat(incidents): add incident support for schemaField - #19115

Merged
AdrianMachado merged 4 commits into
datahub-project:masterfrom
cnpierrepapi:feat-incidents-schemafield
Aug 20, 2026
Merged

AdrianMachado merged 4 commits into
datahub-project:masterfrom
cnpierrepapi:feat-incidents-schemafield

Conversation

@cnpierrepapi

@cnpierrepapi cnpierrepapi commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Closes the schemaField half of the incident entity drift tracked in #18999. Companion to #19112, which does mlModel and mlFeature; @AdrianMachado asked for schemaField to be split into its own PR so it does not block the ML work, and @Danishlynx confirmed on #18999 that it is mine to take.

The gap

schemaField is already a valid incident target. It is in the IncidentOn allowlist in IncidentInfo.pdl, so raiseIncident accepts it and the incident is stored. Nothing could read those incidents back:

layer before after
IncidentOn allowlist (write) yes yes
incidentsSummary aspect no yes
incidents field in GraphQL SDL no yes
entitiesWithIncidents resolver list no yes

The write succeeded and every read reported no incidents.

The type is SchemaFieldEntity, and this one has a decoy

entity.graphql declares two similarly named types:

type SchemaFieldEntity implements EntityWithRelationships & Entity & HasLogicalParent   # the entity
type SchemaField                                                                        # the struct inside schemaMetadata

extend type SchemaField { incidents ... } is not a syntax error and not a build error. It produces a valid schema with an incidents field, so an SDL level check passes. But SchemaField implements no interfaces and is not an entity, so it is never wired in entitiesWithIncidents, the field resolves through the default PropertyDataFetcher, and it returns null with no error.

I checked this rather than assuming it. Assembling all 35 SDL files the way GmsGraphQLEngine does and building the schema with graphql-js:

                    build   SchemaFieldEntity.incidents   types declaring incidents
master              ok      ABSENT                        Chart, Dashboard, DataFlow, DataJob, Dataset
this PR             ok      EntityIncidentsResult         + SchemaFieldEntity
extend SchemaField  ok      (binds to the struct)         + SchemaField

The third row is the failure mode, and it builds cleanly. SchemaFieldEntity reports implements: EntityWithRelationships, Entity, HasLogicalParent; SchemaField reports implements: (none).

@JonathanSolvesProblems this may be worth a line in #19097. The SDL set that check derives is a set of type names, and for this entity one of the plausible names is a decoy that would satisfy the check while resolving nothing.

Authorization is deliberately unchanged

There is no SCHEMA_FIELD_PRIVILEGES in PoliciesConfig, and unlike #19112 there is no existing shape to extend: grep SCHEMA_FIELD over PoliciesConfig.java returns nothing on master. Introducing one would mean inventing per column policy resources, which is a product decision rather than a gap fix.

Per @Danishlynx on #18999, that is also the wrong direction. Column level operations elsewhere already authorize against the parent dataset, for example UpdateDescriptionResolver.updateDatasetSchemaFieldDescription passing the dataset urn into DescriptionUtils.isAuthorizedToUpdateFieldDescription. Columns are governed through their dataset. So this PR changes no authorization at all, and the natural follow up, if maintainers want dataset scoped policies to bind for field incidents, is for the incident resolvers to run the existing EDIT_ENTITY_INCIDENTS check against the parent dataset urn embedded in the schemaField urn. Happy to do that here or as a follow up, whichever you prefer.

Scale

Registering incidentsSummary for schemaField does not materialize an aspect on every column. IncidentsSummaryHook iterates incidentInfo.getEntities() and writes only to the urns an incident actually references, so cost scales with fields that have incidents, not with the number of columns. The registry entry itself is free.

Feature flag

Reading incidents on a field goes through the same path as any other field metadata read in GraphQL, so it depends on schemaFieldEntityFetchEnabled. Raising and resolving are unaffected. This is stated in the entity docs rather than left for people to discover.

What I verified, and what I did not

Verified:

  • the assembled schema builds and SchemaFieldEntity.incidents binds to EntityIncidentsResult with the expected arguments, shown against master as a baseline
  • the decoy behaviour above, by building the wrong version on purpose
  • IncidentsSummaryHook writes only to referenced urns, read from the hook source
  • the entity docs pass prettier under datahub-web-react/.prettierrc.js

Not verified, and I would rather say so than imply otherwise:

  • I have not run a Gradle build or the test suite locally. The Java change is a single entry in an existing ImmutableList, and the SDL block is a structural copy of the existing Chart block, but CI is the first real compile.
  • No resolver test is included yet. EntityIncidentsResolver is entity agnostic and takes the urn from the source entity, so I do not think a new resolver test earns its place, but if you want one in the shape Adrian described for PR1 I will add it.

Leaving this as a draft until @AdrianMachado confirms the authorization call, since that is the only decision here that is not mine to make.

Note for whoever merges second: this and #19112 both edit the entitiesWithIncidents line, so one of them will need a trivial conflict resolution. There is no logical conflict, both are additive.

Checklist


Summary by cubic

Adds incident read support for schema fields. Previously, incidents could be raised on schemaField but GraphQL reads returned none.

  • Registers incidentsSummary for schemaField in entity-registry.yml.
  • Extends SchemaFieldEntity with incidents(...) in incident.graphql and adds it to entitiesWithIncidents resolvers in GmsGraphQLEngine (target the entity type SchemaFieldEntity, not the SchemaField struct).
  • Updates schemaField docs and adds resolver test coverage.

Notes

  • Reads are gated by the schemaFieldEntityFetchEnabled flag; raising/resolving incidents is unchanged.
  • Authorization is unchanged; fields authorize via the parent dataset.

Written for commit ffdefc6. Summary will update on new commits.

Review in cubic

@github-actions github-actions Bot added product PR or Issue related to the DataHub UI/UX community-contribution PR or Issue raised by member(s) of DataHub Community labels Aug 11, 2026
@codecov

codecov Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

@Danishlynx Danishlynx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against what we just did on #19112, since the shape is deliberately the same. The diff matches the verified pattern: the registry entry sits correctly in the schemaField block, SchemaFieldEntity is the right extend target and the right entitiesWithIncidents name (good catch on the decoy, your graphql-js verification table is a nice touch), and skipping PoliciesConfig is right per the #18999 discussion, since there is nothing to extend and columns are governed through their dataset.

One thing worth fixing before undrafting: the docstrings in the new SDL block carry the stale wording the bot review caught on my PR, count described as a start offset and stage and priority as "defaults to any state". I corrected those on the ML blocks in bd45ffc, so suggest the same three lines here so the new block does not reintroduce it: stage "defaults to any stage", priority "defaults to any priority", count "Optional number of results to return, defaults to 20". The five old blocks still carry the stale text, that cleanup can stay a separate change.

On tests: #19112 now parameterizes EntityIncidentsResolverTest on the source entity (assertIncidentsResolvedForSource). Once it merges, a SchemaFieldEntity case is about six lines if a reviewer wants one.

On the entitiesWithIncidents conflict, agreed it is trivial and additive. Happy to rebase whichever of us merges second.

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cnpierrepapi

Copy link
Copy Markdown
Contributor Author

Triage of the one red check, since it does not touch this change.

Playwright E2E (1, 8) failed in the Build images (fork — no depot cache) step, before any test ran. Every subsequent step is skipped, including Run Playwright tests, and no junit.xml was produced, which is why the artifact upload steps report nothing found. The Depot cache steps are skipped for fork PRs, so each shard builds all images from scratch.

The other seven shards built the same images from the same commit and passed. Mergeable is only aggregating the one shard.

Everything that exercises the change is green: codegen-check, all six build-metadata-io backends, the Java SDK V2 integration tests, and Pytest smoke batches 1 and 2. 77 checks green, 1 red.

This was already Attempt #2, so a rerun of that single shard should clear it if someone with access can trigger one. Same failure mode @Danishlynx triaged on #19112 earlier today.

Still a draft pending your call on authorization, @AdrianMachado.

@cnpierrepapi

Copy link
Copy Markdown
Contributor Author

Thanks, and taken on all three.

Docstrings: fixed in 20d4a31, matching your corrected wording exactly, so stage reads "defaults to any stage", priority "defaults to any priority", and count "Optional number of results to return, defaults to 20". You are right about how it got there: I copied the Chart block structurally on purpose, so I inherited the stale text along with the shape. Left the five pre-existing blocks alone, same call you made.

Tests: that is the better sequencing. I will add the SchemaFieldEntity case to assertIncidentsResolvedForSource once #19112 merges, rather than writing a parallel fixture now and forcing someone to reconcile two of them.

Conflict: agreed, and since yours is further along, I will rebase this one rather than the other way round.

While we are on the incident docstrings, one thing your fix surfaced that may be worth a line in the follow-up: the stale wording came from the five original blocks, and there are now two blocks with corrected wording and five without. Worth cleaning the five in one pass rather than each new entity inheriting the old text and being corrected in review, which is twice now.

Still a draft pending @AdrianMachado on the authorization question from #18999. For what it is worth, Adrian already listed schemaField under related cleanup on #18911 back on Aug 6 ("same incomplete pattern, relationship allowed, no summary"), so the direction is not in doubt; it is only the authorization call that is open, and per your UpdateDescriptionResolver precedent I expect that to be "leave it alone".

@Danishlynx

Copy link
Copy Markdown
Contributor

All sounds right, and thanks for the quick turnaround on the docstrings.

On the five stale blocks: agreed it should be one pass instead of correcting each new entity in review. Happy to take that as a small docs-only follow-up once this and #19112 have both landed, so it conflicts with neither; at that point your block and my two already carry the corrected text and exactly the five originals remain. If Jonathan would rather also have #19097 nudge new blocks toward the corrected wording, even better, but the one-pass cleanup stands either way.

@cnpierrepapi

Copy link
Copy Markdown
Contributor Author

Ran the six surfaces against master (a43a096) with a script rather than by hand, since a hand-derived table here has already been wrong once. Posting the schemaField row for the #19097 scope notes, @Danishlynx.

schemaField on master

surface schemaField
IncidentOn allowlist, IncidentInfo.pdl yes, already there via #18478
incidentsSummary in entity-registry.yml no
extend type in incident.graphql no
entitiesWithIncidents in GmsGraphQLEngine no
activeIncidents badge alias no
getEntityIncidents inline fragments no

This PR covers the middle three. The two frontend surfaces are untouched, and that is deliberate: SchemaFieldEntity.tsx does not register IncidentTab, so unlike MLModelEntity and MLFeatureEntity there is no tab already visible with nothing behind it. The API lands first and the UI stays a clean follow-up rather than a repair.

Two things the derivation turned up that are outside this PR

service and aiAgent sit in the same state the ML entities were in: present in the PDL allowlist, incidentsSummary registered, and absent from the other four surfaces. That may be the sixth type @JonathanSolvesProblems flagged on #18999. Neither is claimed by #18911, #19112 or this PR.

Complete across all six surfaces today: dataset, chart, dashboard, dataFlow, dataJob. Five of the ten in the allowlist.

One detail on the parse, worth carrying into #19097. The badge alias is declared inside a fragment for dataset, dataFlow and dataJob, but directly inside a query for chart and dashboard. My first pass attributed each occurrence to the nearest preceding fragment and duly reported chart and dashboard as missing the alias, which is false. That is the same fragment-versus-file trap as #19117, reproduced inside a script written to catch it, and I only noticed because it contradicted your list. A guardrail here has to attribute by enclosing block and resolve spreads transitively, never scan per file.

Still a draft pending @AdrianMachado on the authorization question from #18999.

@AdrianMachado

Copy link
Copy Markdown
Contributor

@cnpierrepapi answering the auth question so this doesn’t stay a draft for that.

This PR stays gates 2–4 only. No SCHEMA_FIELD_PRIVILEGES, no getEntityIncidents / badge, no tab. SchemaField has no Incidents tab today, so the API-first split is right — unlike ML, you aren’t shipping a broken UI.

Auth: leave it. Don’t invent per-column policy resources. raiseIncident already checks EDIT_ENTITY_INCIDENTS on the resource URN, so a dataset-scoped policy will not match a schemaField URN. That’s a real gap, but it belongs in a follow-up that extracts the parent dataset from the field URN and runs the existing check there (same pattern as UpdateDescriptionResolver). Not this PR.

After #19112 merges: rebase (you’ll conflict on entitiesWithIncidents / incident.graphql / registry — additive), and add a SchemaFieldEntity case to assertIncidentsResolvedForSource. Don’t rebase now.

Don’t stack this on #19112 — different authors, both targeting master. Native GitHub stacks are for one person’s layer chain.

@AdrianMachado

Copy link
Copy Markdown
Contributor

Plan is on #19322. This PR stays schemaField gates 2–4. Rebase after #19112; add the SchemaFieldEntity resolver test then. Auth call already landed in the previous comment.

@AdrianMachado

Copy link
Copy Markdown
Contributor

#19112 merged, so this PR is now CONFLICTING (expected: entitiesWithIncidents, incident.graphql, entity-registry.yml).

Please rebase onto master, keep gates 2–4 only, and add a SchemaFieldEntity case to assertIncidentsResolvedForSource (that helper landed in 19112). Auth stays as discussed: no SCHEMA_FIELD_PRIVILEGES.

@cnpierrepapi

schemaField has been a valid incident target in the IncidentOn allowlist in
IncidentInfo.pdl, but nothing could read those incidents back. The entity had
no incidentsSummary aspect, no incidents field in the GraphQL SDL, and no entry
in the resolver list in GmsGraphQLEngine, so writes succeeded and every read
reported nothing.

This closes the read path:

- register incidentsSummary for schemaField in entity-registry.yml
- extend SchemaFieldEntity with an incidents field in incident.graphql
- add SchemaFieldEntity to entitiesWithIncidents in GmsGraphQLEngine
- document the capability in the entity docs

The GraphQL type is SchemaFieldEntity, not SchemaField. Both types exist:
SchemaFieldEntity is the entity, while SchemaField is the struct carried inside
schemaMetadata. Extending SchemaField parses and builds a valid schema, but the
field would resolve through the default PropertyDataFetcher and return null,
since only entities are wired in entitiesWithIncidents.

Authorization is deliberately unchanged. There is no SCHEMA_FIELD_PRIVILEGES
resource in PoliciesConfig, and column level operations elsewhere authorize
against the parent dataset, so no per column policy resource is introduced here.

Reading incidents on a field depends on the schemaFieldEntityFetchEnabled
feature flag, as with any other field metadata read through GraphQL.

@AdrianMachado AdrianMachado left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase after #19112 looks right, and the resolver test case is in. Approving the code; still a draft — undraft when you want it in the merge queue.

Six gates (schemaField)

Gate This PR
1 Write (IncidentOn) already master (#18478)
2 Summary incidentsSummary on schemaField ✓
3 SDL extend type SchemaFieldEntity (not the SchemaField decoy) ✓
4 Resolver "SchemaFieldEntity" in entitiesWithIncidents ✓
5 Badge / 6 Tab correctly out — no Incidents tab on SchemaFieldEntity today

builder.type("SchemaFieldEntity", …) will merge with the existing SchemaFieldEntity wiring (~line 2267). Same pattern as ML.

Docstrings match the corrected ML wording (stage/priority/count). Docs call out schemaFieldEntityFetchEnabled. Auth unchanged as agreed — no SCHEMA_FIELD_PRIVILEGES; parent-dataset check stays a follow-up.

CI

Cancelled runs are not this diff. Same infra pattern as #19112: jobs stuck on Install dependencies / Playwright deps (GitHub-hosted), then cancelled (some after ~1h, smoke after ~6h). metadata-io, build & test, codegen, and several integration shards did pass. Re-run failed/cancelled workflows when you undraft; don’t change the PR for it.

Ship after undraft + green (or override the same flakes).

@AdrianMachado
AdrianMachado marked this pull request as ready for review August 20, 2026 05:16
@github-actions

Copy link
Copy Markdown
Contributor

Linear: OBS-2087

Thanks for your contribution! We have created an internal ticket to track this PR. A member of the core DataHub team will be assigned to review it within the next few business days - you will get a follow-up comment once a reviewer is assigned.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 5 files

Re-trigger cubic

@AdrianMachado
AdrianMachado enabled auto-merge (squash) August 20, 2026 05:29
@github-actions
github-actions Bot requested a review from AdrianMachado August 20, 2026 05:44
@github-actions

Copy link
Copy Markdown
Contributor

Your PR has been assigned to @AdrianMachado (adrian.machado) for review (OBS-2087).

@maggiehays maggiehays added the merge-pending-ci A PR that has passed review and should be merged once CI is green. label Aug 20, 2026

This branch was successfully deployed

1 active deployment
Preview — ffdefc64 Deployed Aug 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution PR or Issue raised by member(s) of DataHub Community merge-pending-ci A PR that has passed review and should be merged once CI is green. product PR or Issue related to the DataHub UI/UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants