Skip to content

chore: share constants between backend and frontend via JSON - #935

Open
Bhavd33p wants to merge 2 commits into
kubeflow:mainfrom
Bhavd33p:chore/shared-rpc-error-codes-925
Open

chore: share constants between backend and frontend via JSON#935
Bhavd33p wants to merge 2 commits into
kubeflow:mainfrom
Bhavd33p:chore/shared-rpc-error-codes-925

Conversation

@Bhavd33p

Copy link
Copy Markdown
Contributor

Summary

  • kale/rpc/errors.py's Code enum and labextension/src/lib/RPCUtils.tsx's RPC_CALL_STATUS enum independently hardcoded the same seven name→int error-code mappings. Nothing would catch it if one side changed a value (or added/removed a code) without updating the other — exactly the kind of drift risk described in the issue.
  • Added kale/rpc/error_codes.json as the single source of truth for these values.
    • Backend: Code's member values are now read from the JSON at import time (kept as an explicit enum.Enum class body, rather than building the enum dynamically from the dict, so Code.SERVICE_UNAVAILABLE etc. stay fully statically type-checkable).
    • Frontend: RPC_CALL_STATUS's member values are now read from the same JSON via a relative import (../../../kale/rpc/error_codes.json). This only needs the file to exist in the repo at build time — webpack/tsc bake the JSON's contents into the compiled output, so there's no runtime dependency between the built labextension and the Python package's file layout (verified: tsc --noEmit, tsc with emit, and the full jlpm build webpack bundle all resolve it cleanly, and the compiled bundle contains the baked-in values).
  • Added a backend test that asserts Code's values match the JSON, so a future hardcoded edit that skips the JSON gets caught.

I picked this as the first (smallest, self-contained) case to tackle out of several duplicated-constant instances I found while looking into this — happy to follow up with others (e.g. the cell-tag vocabulary in kale/processors/nbprocessor.py vs labextension/src/widgets/cell-metadata/constants.ts) in separate PRs, since that one overlaps with the in-flight #909 (nbprocessor constants extraction) and deserves its own focused pass.

Fixes #925

Test plan

  • pytest kale/tests/unit_tests — 269 passed (268 + new test).
  • ruff check kale / ruff format --check kale pass.
  • tsc --noEmit, eslint:check, prettier:check pass.
  • jest passes.
  • Full jlpm build (webpack) succeeds; confirmed the compiled bundle contains the JSON's values (grep SERVICE_UNAVAILABLE on the built lib_index_js.*.js).

kale/rpc/errors.py's Code enum and labextension's RPC_CALL_STATUS enum
independently hardcoded the same seven name-to-int mappings, with
nothing to catch them drifting apart if one side changed without the
other.

Move the mapping into kale/rpc/error_codes.json and have both sides
read their values from it: the backend at import time, the frontend
via a relative import resolved at build time (webpack/tsc bundle the
JSON's contents into the compiled output, so there's no runtime
dependency on the Python package's file layout). Add a test asserting
Code's values match the JSON, to catch anyone reverting to hardcoded
values on the backend side.

Signed-off-by: [Bhavdeep Singh] <bhavdeep3singh@gmail.com>
@google-oss-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign stefanofioravanzo for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ada333 ada333 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.

Hi @Bhavd33p this is great start, in the issue I meant string constants like cell tags, tags prefixes, default base image... that are both in FE and BE. Are you planning to also implement it in this PR?

@ederign

ederign commented Aug 13, 2026

Copy link
Copy Markdown
Member

@Bhavd33p thanks for working on this, one thing that I want to ask, is that we do this fix in a proper way adding 'human' messages to folks understand in the UI whats is going on. (instead of machine errors)

Extend the shared JSON from RPC error codes to every constant that was
defined once in Python and once in TypeScript: the reserved cell names,
the cell tag prefixes, the step name pattern, the cache/report tag values,
the notebook metadata key and the default base image. Rename the file to
kale/shared_constants.json accordingly, read it on the backend through
kale/shared_constants.py and on the frontend through
labextension/src/lib/sharedConstants.ts.

The notebook processor now assembles its tag patterns from the shared
prefixes instead of spelling them out; test_shared_constants.py pins the
tags that must keep being accepted and rejected.

The shared file also carries a plain-language explanation per error code,
and the RPC dialog leads with it instead of with a numeric code, so users
read what went wrong. The diagnostics stay, below the explanation.

Signed-off-by: Bhavdeep Singh <bhavdeep3singh@gmail.com>
@Bhavd33p

Bhavd33p commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @ada333 @ederign — both asks are in now.

@google-oss-prow google-oss-prow Bot added size/XL and removed size/M labels Aug 19, 2026
@Bhavd33p Bhavd33p changed the title chore: share RPC error codes between backend and frontend via JSON chore: share constants between backend and frontend via JSON Aug 19, 2026
@harshhh817

Copy link
Copy Markdown
Contributor

Read through the backend side of this. The JSON-as-single-source approach looks right to me, and the test asserting Code matches the JSON is the part that makes it actually hold. Three things, one of which I think is a real (pre-existing) gap this PR is about to enshrine.

1. The new comment on KALE_TAG_PREFIXES doesn't match the backend.

// `annotation:` and `label:` are deliberately absent - the backend only accepts
// those in the notebook-level `steps_defaults`, never on a cell.

parse_cell_metadata does handle both on a cell — it collects them into cell_annotations/cell_labels and only rejects them when the cell has no step name. Checked against current main:

cell tags: step:one + annotation:foo/bar:baz + label:team:ml
  parsed annotations -> {'foo/bar': 'baz'}
  parsed labels      -> {'team': 'ml'}

That matters because KALE_TAG_PREFIXES is what TagsUtils.ts:336 uses to "Clear all Kale tags from the active cell". So a cell carrying annotation:/label: keeps those tags after the clear — they're Kale's tags, but nothing recognises them as such.

notebook: looks like the same gap since #867 landed — the backend parses it on a cell (tag_name == "notebook"), and it isn't in CELL_TAG_PREFIXES either.

Both predate this PR, so not something you broke. But since this is the change that centralises the list, is it worth adding them to tag_prefixes here — or at least dropping the rationale in that comment, so the omission stays a known gap rather than becoming documented intent?

2. The description has drifted from the diff. It describes adding kale/rpc/error_codes.json for the seven error codes; what's actually here is kale/shared_constants.json covering error explanations, cell tag prefixes, reserved names, the step-name pattern, the notebook metadata key and the default base image. Given the review surface is a fair bit larger than the summary implies, might be worth refreshing it.

3. Coordination question, and I should declare an interest here — I'm the author of #909, which moves the nbprocessor.py constants block into kale/processors/constants.py. This PR introduces kale/shared_constants.py covering some of the same ground (NB_METADATA_KEYKALE_NB_METADATA_KEY, TAG_ENABLED_VALUE/TAG_DISABLED_VALUECACHE_ENABLED/REPORT_ENABLED), and both edit the same block, so they'll conflict whichever lands first.

They don't seem to be in tension conceptually — yours is "values the frontend must agree on," mine is "values nbprocessor shouldn't hardcode" — so the natural layering might be for constants.py to source the shared ones from shared_constants. But that's a call for @ada333/@jesuino rather than something either of us should decide unilaterally. Happy to rebase mine on top of yours if this goes first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: Have shared json file for constants used both in backend and frontend code

4 participants