Skip to content

Remove redundant dfiq_type request field from DFIQ create/validate/patch - #1340

Merged
tomchop merged 2 commits into
mainfrom
fix/dfiq-remove-redundant-type-field
Aug 8, 2026
Merged

Remove redundant dfiq_type request field from DFIQ create/validate/patch#1340
tomchop merged 2 commits into
mainfrom
fix/dfiq-remove-redundant-type-field

Conversation

@tomchop

@tomchop tomchop commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Every DFIQ create/validate/patch request already carries the object's type embedded in its dfiq_yaml body (type: scenario|facet|question). The separate dfiq_type request field duplicated that:
    • On /from_yaml and /validate, it only selected which pydantic subclass parsed the YAML, and that subclass already re-checks its own type: field and raises ValueError on mismatch -- so the parameter could only ever agree with the YAML or cause a 400. DFIQBase.from_yaml (used by the batch/feed ingestion path, read_from_data_directory) already dispatches on the YAML's own embedded type with no separate parameter, proving one isn't needed here either.
    • On PATCH /{id}, it was outright dead: the handler dispatches on db_dfiq.type (the object's existing type from the database), never reads request.dfiq_type, yet every caller was required to send it (confirmed by grep -- only the two declaration lines referenced it).
  • Switches /from_yaml and /validate to the existing generic DFIQBase.from_yaml dispatcher, and drops dfiq_type from all three request schemas. extra="forbid" on these models means callers must stop sending it, hence the mechanical test-payload cleanup (no test exercised type-mismatch behavior, so this isn't a coverage change).
  • Also tightens DFIQBase.from_yaml itself to parse via parse_yaml (which every subclass's own from_yaml already does) instead of a bare yaml.safe_load -- needed so a malformed/missing type now raises the same ValueError every other path already guarantees, rather than an uncaught KeyError/YAMLError this generic dispatcher previously let through. Relevant now that /from_yaml and /validate lean on it more.

Paired with a frontend fix ([yeti-feeds-frontend#TBD]) that stops sending dfiq_type and fixes a real UI inconsistency this same redundancy was masking: the frontend's own localObject.type was frozen at dialog-open time while the "Approaches" tab's visibility tracked the live YAML, so hand-editing the raw YAML tab's type: field (a first-class, unguarded editing path) made the Approaches tab and the Parents field visibly disagree about the object's type.

Test plan

  • tests/apiv2/dfiq.py -- 18/18 pass
  • tests/apiv2/timeline.py -- pass
  • Full CI-parity suite (tests/schemas, tests/apiv2, tests/core_tests) -- zero new failures vs a clean origin/main baseline run the same way (pre-existing environmental failures only: bloomcheck config, missing system config section, missing default-group seed data in this throwaway container -- confirmed identical failure count on baseline)
  • ruff check/ruff format --check clean on every touched line (repo has a large pre-existing lint backlog elsewhere, unrelated)
  • Confirmed via generated OpenAPI schema that dfiq_type no longer appears on NewDFIQRequest/DFIQValidateRequest/PatchDFIQRequest
  • End-to-end verified against the paired frontend fix: DFIQ scenario creation succeeds through the real UI without sending dfiq_type, and toggling a Question's raw YAML type: to facet correctly flips the Approaches tab and Parents field into agreement (previously they'd disagree)

Every DFIQ create/validate/patch request already carries the object's
type embedded in its dfiq_yaml body (`type: scenario|facet|question`).
The separate `dfiq_type` request field duplicated that:

- On /from_yaml and /validate, it only selected which pydantic subclass
  parsed the YAML, and that subclass already re-checks its own `type:`
  field and raises ValueError on mismatch -- so the parameter could
  only ever agree with the YAML or cause a 400. DFIQBase.from_yaml
  (used by the batch/feed ingestion path) already dispatches on the
  YAML's own embedded type with no separate parameter, proving one
  isn't needed here either.
- On PATCH /{id}, it was outright dead: the handler dispatches on
  db_dfiq.type (the object's existing type from the database), never
  reads request.dfiq_type, yet every caller was required to send it.

Switches /from_yaml and /validate to the existing generic
DFIQBase.from_yaml dispatcher, and drops dfiq_type from all three
request schemas (extra="forbid" means callers must stop sending it,
hence the test updates -- no test exercised type-mismatch behavior, so
this is a mechanical payload cleanup, not a coverage change).

Also tightens DFIQBase.from_yaml itself to parse via parse_yaml (which
every subclass's own from_yaml already does) instead of a bare
yaml.safe_load -- needed so a malformed/missing 'type' now raises the
same ValueError every other path already guarantees, rather than an
uncaught KeyError/YAMLError this generic dispatcher previously let
through (relevant now that /from_yaml and /validate lean on it more).

Paired with a frontend fix (yeti-feeds-frontend) that stops sending
dfiq_type and fixes a real UI inconsistency the same redundancy was
masking (Approaches tab and Parents field disagreeing about an
object's type when its raw YAML is hand-edited).

Verified: full tests/apiv2/dfiq.py (18/18) and tests/apiv2/timeline.py
pass; tests/schemas, tests/apiv2, tests/core_tests show zero new
failures vs a clean origin/main baseline (pre-existing environmental
failures only: bloomcheck config, missing system config, missing
default group seed data); ruff clean on all touched lines; confirmed
via generated OpenAPI schema that dfiq_type no longer appears on
NewDFIQRequest/DFIQValidateRequest/PatchDFIQRequest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011tXLywVq32tGPE7jCrdZVJ
Comment thread core/schemas/dfiq.py Outdated
Comment on lines +243 to +247
# parse_yaml (not a bare yaml.safe_load) so a malformed/missing/
# unrecognized 'type' raises the same ValueError every subclass's own
# from_yaml already guarantees, instead of a KeyError/YAMLError this
# generic dispatcher used to let through uncaught.
yaml_data = cls.parse_yaml(yaml_string)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Remove

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011tXLywVq32tGPE7jCrdZVJ
@tomchop
tomchop merged commit 150aa9c into main Aug 8, 2026
5 checks passed
@tomchop
tomchop deleted the fix/dfiq-remove-redundant-type-field branch August 8, 2026 21:11
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