Skip to content

Remove org_id from goal/session models, DTOs (OpenAPI), and the goal-issue marker #272

@chronoai-shining

Description

@chronoai-shining

Summary

Delete the NyxID-org org_id field from the goal/session models (GoalDoc, the cross-crate SessionDoc), the HTTP DTOs (CreateGoalRequest, GoalView, SessionView) — which drops the org_id property from the runtime-generated OpenAPI schemas — and the goal-issue hidden marker (GoalMarker), with parse-and-ignore backward-compat for already-filed goal issues. Also remove every internal carrier that threads the field.

This is the third PR. It depends on #270 (which already dropped Ownership.org_id, so the Ownership builders in goals.rs/sessions.rs compile without the field) and must be co-committed with the session-dispatch consumers (the service.rs SessionDoc{org_id} construction etc.) so the workspace compiles after SessionDoc.org_id is deleted. The vault/codex_provider pure pass-through params are #273 (they don't read org_id, so they can lag).

Problem / Motivation

Backward-compat (the subtle part) — parse-and-ignore, NO version bump

A goal is durably mirrored as a GitHub Issue whose body carries a v:1 JSON marker historically including "org_id":.... CRITICAL FINDING: parse_marker has no production read-back caller (only unit tests call it; the in-memory GoalIssueStore is authoritative and does not rehydrate goals from issues on boot). GoalMarker has no #[serde(deny_unknown_fields)], so serde silently drops a leftover org_id key in any pre-removal body. Therefore: keep marker v:1, just remove the field from GoalMarker + render_marker. A version bump to v:2 or adding deny_unknown_fields would make parse_marker reject every already-filed goal issue (UnsupportedVersion/unknown-field) — explicitly forbidden. SessionDoc likewise has no deny_unknown_fields, so legacy session docs carrying org_id still deserialize.

Proposed Solution — Implementation Spec

backend/fkst-control-plane/src/goals/model.rs

  1. L66-68 delete pub org_id: Option<String> + its doc-comment from GoalDoc. Keep owner_user_id and repo: Option<RepoRef> (the GitHub repo — KEEP).
  2. Tests: sample_goal_doc() drop org_id: None (L197); explicit_null_fields_serialize_as_null drop the raw.get("org_id")...Bson::Null assertion (L233-234); set_fields_round_trip drop doc.org_id = Some("org-1") (L248).

backend/fkst-control-plane/src/goals/marker.rs

  1. L26-34 delete GoalMarker.org_id (L31). Keep v, goal_id, owner_user_id, package_names, repo.
  2. L48-59 render_marker: delete org_id: doc.org_id.clone() (L53). Keep v: 1 — do NOT bump.
  3. L63-86 parse_marker: NO logic change (no deny_unknown_fields, so an old body with "org_id" still parses and the key is ignored).
  4. L1-15 module doc + L13 example literal: remove the org_id key from the documented marker shape and the owner/org/packages/repo prose.
  5. Tests: goal() fixture drop org_id: Some("org-9") (L105); marker_round_trips drop the org_id assertion (L120). The marker_v2_unsupported (L148-154) / marker_hand_edited_invalid_package_rejected (L156-166) literals carry "org_id":null — leave them (they still parse). ADD marker_old_body_with_org_id_parses_and_ignores_it: feed {"v":1,...,"org_id":"org-9",...}, assert Ok and that the parsed struct exposes no org_id. ADD a render test asserting render_marker(doc) output does NOT contain the substring org_id.

backend/fkst-shared/src/models/mod.rs (cross-crate)

  1. L82-85 delete SessionDoc.org_id (with its #[serde(default, skip_serializing_if = "Option::is_none")]) + doc-comment. No cfg_attr/schema-feature change needed (removing a field is schema-safe for both control-plane and the worker).
  2. Tests: drop org_id: None from the sample fixture (L184); update ownership_fields_are_omitted_when_absent (drop the org_id-omitted assertion, L305-308), ownership_fields_round_trip_when_set (drop doc.org_id = Some("org-1") + assert, L315/L321), legacy_docs_without_ownership_fields_still_deserialize (drop raw.remove("org_id") + back.org_id == None, L330/L333). Keep/ADD a regression test that a serialized SessionDoc with a stray org_id key still deserializes (back-compat with already-persisted org-tagged docs).

backend/fkst-control-plane/src/routes/goals.rs

  1. Delete CreateGoalRequest.org_id (L64-66) and GoalView.org_id (L104) — both #[derive(ToSchema)], so org_id leaves those component schemas in /openapi.json.
  2. TryFrom<GoalDoc> for GoalView (L231-252): drop org_id: doc.org_id (L246).
  3. create handler: drop org_id: request.org_id from the constructed GoalDoc literal (L346). (The require_org_writer block at L311-314 was already removed in Strip NyxID-org authz: remove visible_org_ids/require_org_writer/OrgRole branches (owner-only) #270.)
  4. trigger handler: drop org_id: goal.org_id.clone() from the GoalTriggerInfo literal (L1140).
  5. Tests: owned_goal(owner, org)owned_goal(owner) (drop the org field, L1298-1312); goal_ownership_is_sub_keyed_and_never_ownerless drop the org_id assertion; goal_view_emits_explicit_nulls drop body["org_id"].is_null() (L1355) and the org_id: None seed; goal_view_status_is_snake_case drop the seed (L1372). KEEP — DO NOT TOUCH: CreateRepoSpecBody.org_login (L216-218), CreateRepoSpec.org_login, is_org_repo, the org_login idempotency match, install_hint_message wording (GitHub org).

backend/fkst-control-plane/src/routes/sessions.rs

  1. Delete SessionView.org_id (L58-59) + its doc-comment (ToSchema → leaves the schema). TryFrom<&SessionDoc> for SessionView: drop org_id: doc.org_id.clone() (L88).
  2. authorize_session_read/authorize_session_write: drop org_id: session.org_id.as_deref() from the Ownership literals (L218, L240) — required because Strip NyxID-org authz: remove visible_org_ids/require_org_writer/OrgRole branches (owner-only) #270 removed Ownership.org_id. Update the doc-comments (L113-118, L158-160, L204-208, L227-230) from "Org members can read/stop" to owner+admin only.
  3. Test session_view_emits_explicit_nulls_and_z_suffixed_timestamps: drop org_id: None from the SessionDoc literal (L282) and "org_id" from the explicit-null list (L305). Add an assertion that the serialized SessionView has no org_id key.

backend/fkst-control-plane/src/routes/goals_submit.rs

  1. build_goal (L312-337): drop org_id: None (L332) + its stale comment (L329-331). Drop org_id: goal.org_id.clone() from the other GoalTriggerInfo literal (L182). (The authorize_object org-writer arm was already removed in Strip NyxID-org authz: remove visible_org_ids/require_org_writer/OrgRole branches (owner-only) #270.)

backend/fkst-control-plane/src/sessions/service.rs (co-committed dispatch consumers)

  1. struct SessionOwner (L63-67): drop org_id (L66). If it has no non-test constructor after the classic-POST-/sessions removal, prefer shrinking to a one-field wrapper (do not delete the type unless confirmed dead and the re-export at sessions/mod.rs:22 is updated).
  2. struct GoalTriggerInfo (L71-83): drop org_id (L76).
  3. create_for_goal SessionDoc construction: drop org_id: trigger.org_id.clone() (L596).
  4. Test fixtures: drop org_id: None (L3166) and the doc-comment mention (L3152). (The list_for_scope/resolve_provider_choice arg removals at L2300/L2334 are Drop the no-op org_id pass-through params from vault/codex_provider/session dispatch #273 — they still compile here passing session.org_id.as_deref() only until SessionDoc.org_id is gone; therefore in THIS PR change those two calls to drop the now-deleted-field arg as part of the co-commit, OR keep Drop the no-op org_id pass-through params from vault/codex_provider/session dispatch #273 folded into this PR. Pick one and state it; default: change L2300/L2334 here to pass no org arg, and let Drop the no-op org_id pass-through params from vault/codex_provider/session dispatch #273 drop the underlying params.)

Also co-commit the remaining SessionDoc { org_id: None } literals the compiler surfaces in sessions/dispatch_tests.rs (L136/L177), sessions/repo_tests.rs (L22), and any integration test fixtures (tests/sessions_api.rs, tests/admin_metrics.rs, tests/goal_session_token.rs, tests/github_app_installations.rs, tests/activation_dispatch.rs, tests/claim_placement.rs, tests/reassign_redispatch.rs) — pure struct-seed updates (these may instead be swept in #274 if that keeps this PR focused; if so, this PR will not compile until #274 lands, so prefer folding the seed updates here).

Scope Check

API / Persistence Impact

Acceptance Criteria / Definition of Done

  • GoalDoc, SessionDoc, CreateGoalRequest, GoalView, SessionView, GoalMarker carry no org_id.
  • Marker stays v:1; marker_old_body_with_org_id_parses_and_ignores_it and the no-org_id-in-render test pass; a SessionDoc with a stray org_id key still deserializes.
  • cargo test -p fkst-control-plane -p fkst-shared green; cargo build -p fkst-worker green; the generated /openapi.json no longer advertises org_id on the four DTOs (org_login preserved on repo-create).
  • Workspace compiles at the commit boundary (co-commit the cross-crate SessionDoc consumers).

Metadata

Metadata

Labels

backendRust/Axum backend worksa:downstream-authzsa-design context: downstream proxy-trust auth + RBACtype:refactorInternal restructuring; no functional change.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions