From e36b49a31e145c2d0d9e9e23afa284bcb92e22c3 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 31 Mar 2025 16:00:23 -0700
Subject: [PATCH 1/7] submissions: datastore: duplicate submissions as mapfixes

---
 pkg/datastore/datastore.go           |  12 +++
 pkg/datastore/gormstore/gormstore.go |   4 +
 pkg/datastore/gormstore/mapfixes.go  | 132 +++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 pkg/datastore/gormstore/mapfixes.go

diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go
index 8a256b1..1cc3f48 100644
--- a/pkg/datastore/datastore.go
+++ b/pkg/datastore/datastore.go
@@ -22,11 +22,23 @@ const (
 )
 
 type Datastore interface {
+	Mapfixes() Mapfixes
 	Submissions() Submissions
 	Scripts() Scripts
 	ScriptPolicy() ScriptPolicy
 }
 
+type Mapfixes interface {
+	Get(ctx context.Context, id int64) (model.Mapfix, error)
+	GetList(ctx context.Context, id []int64) ([]model.Mapfix, error)
+	Create(ctx context.Context, smap model.Mapfix) (model.Mapfix, error)
+	Update(ctx context.Context, id int64, values OptionalMap) error
+	IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) error
+	IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) (model.Mapfix, error)
+	Delete(ctx context.Context, id int64) error
+	List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Mapfix, error)
+}
+
 type Submissions interface {
 	Get(ctx context.Context, id int64) (model.Submission, error)
 	GetList(ctx context.Context, id []int64) ([]model.Submission, error)
diff --git a/pkg/datastore/gormstore/gormstore.go b/pkg/datastore/gormstore/gormstore.go
index 6b1f9d9..da16895 100644
--- a/pkg/datastore/gormstore/gormstore.go
+++ b/pkg/datastore/gormstore/gormstore.go
@@ -9,6 +9,10 @@ type Gormstore struct {
 	db *gorm.DB
 }
 
+func (g Gormstore) Mapfixes() datastore.Mapfixes {
+	return &Mapfixes{db: g.db}
+}
+
 func (g Gormstore) Submissions() datastore.Submissions {
 	return &Submissions{db: g.db}
 }
diff --git a/pkg/datastore/gormstore/mapfixes.go b/pkg/datastore/gormstore/mapfixes.go
new file mode 100644
index 0000000..d80067e
--- /dev/null
+++ b/pkg/datastore/gormstore/mapfixes.go
@@ -0,0 +1,132 @@
+package gormstore
+
+import (
+	"context"
+	"errors"
+
+	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
+	"git.itzana.me/strafesnet/maps-service/pkg/model"
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+)
+
+type Mapfixes struct {
+	db *gorm.DB
+}
+
+func (env *Mapfixes) Get(ctx context.Context, id int64) (model.Mapfix, error) {
+	var mapfix model.Mapfix
+	if err := env.db.First(&mapfix, id).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return mapfix, datastore.ErrNotExist
+		}
+		return mapfix, err
+	}
+	return mapfix, nil
+}
+
+func (env *Mapfixes) GetList(ctx context.Context, id []int64) ([]model.Mapfix, error) {
+	var mapList []model.Mapfix
+	if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
+		return mapList, err
+	}
+
+	return mapList, nil
+}
+
+func (env *Mapfixes) Create(ctx context.Context, smap model.Mapfix) (model.Mapfix, error) {
+	if err := env.db.Create(&smap).Error; err != nil {
+		return smap, err
+	}
+
+	return smap, nil
+}
+
+func (env *Mapfixes) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
+	if err := env.db.Model(&model.Mapfix{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return datastore.ErrNotExist
+		}
+		return err
+	}
+
+	return nil
+}
+
+// the update can only occur if the status matches one of the provided values.
+func (env *Mapfixes) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.MapfixStatus, values datastore.OptionalMap) error {
+	if err := env.db.Model(&model.Mapfix{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map()).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return datastore.ErrNotExist
+		}
+		return err
+	}
+
+	return nil
+}
+
+// the update can only occur if the status matches one of the provided values.
+// returns the updated value
+func (env *Mapfixes) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values datastore.OptionalMap) (model.Mapfix, error) {
+	var mapfix model.Mapfix
+	result := env.db.Model(&mapfix).
+		Clauses(clause.Returning{}).
+		Where("id = ?", id).
+		Where("status_id IN ?", statuses).
+		Updates(values.Map())
+	if result.Error != nil {
+		if result.Error == gorm.ErrRecordNotFound {
+			return mapfix, datastore.ErrNotExist
+		}
+		return mapfix, result.Error
+	}
+
+	if result.RowsAffected == 0 {
+		return mapfix, datastore.ErroNoRowsAffected
+	}
+
+	return mapfix, nil
+}
+
+func (env *Mapfixes) Delete(ctx context.Context, id int64) error {
+	if err := env.db.Delete(&model.Mapfix{}, id).Error; err != nil {
+		if err == gorm.ErrRecordNotFound {
+			return datastore.ErrNotExist
+		}
+		return err
+	}
+
+	return nil
+}
+
+func (env *Mapfixes) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) ([]model.Mapfix, error) {
+	var maps []model.Mapfix
+
+	db := env.db
+
+	switch sort {
+	case datastore.ListSortDisabled:
+		// No sort
+		break
+	case datastore.ListSortDisplayNameAscending:
+		db=db.Order("display_name ASC")
+		break
+	case datastore.ListSortDisplayNameDescending:
+		db=db.Order("display_name DESC")
+		break
+	case datastore.ListSortDateAscending:
+		db=db.Order("created_at ASC")
+		break
+	case datastore.ListSortDateDescending:
+		db=db.Order("created_at DESC")
+		break
+	default:
+		return nil, datastore.ErrInvalidListSort
+	}
+
+	if err := db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
+		return nil, err
+	}
+
+	return maps, nil
+}
-- 
2.47.1


From 2e65d071e0b5277d5b6980ad3bc323e86e87a583 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 31 Mar 2025 15:16:10 -0700
Subject: [PATCH 2/7] openapi: mapfixes

---
 openapi-internal.yaml |  97 ++++++++++++
 openapi.yaml          | 344 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 441 insertions(+)

diff --git a/openapi-internal.yaml b/openapi-internal.yaml
index 91cf730..c47f030 100644
--- a/openapi-internal.yaml
+++ b/openapi-internal.yaml
@@ -4,9 +4,98 @@ info:
   description: Internal operations inaccessible from the public internet.
   version: 0.1.0
 tags:
+  - name: Mapfixes
+    description: Mapfix operations
   - name: Submissions
     description: Submission operations
 paths:
+  /mapfixes/{MapfixID}/validated-model:
+    post:
+      summary: Update validated model
+      operationId: updateMapfixValidatedModel
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+        - name: ValidatedModelID
+          in: query
+          required: true
+          schema:
+            type: integer
+            format: int64
+        - name: ValidatedModelVersion
+          in: query
+          required: true
+          schema:
+            type: integer
+            format: int64
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/validator-validated:
+    post:
+      summary: (Internal endpoint) Role Validator changes status from Validating -> Validated
+      operationId: actionMapfixValidated
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/validator-failed:
+    post:
+      summary: (Internal endpoint) Role Validator changes status from Validating -> Accepted
+      operationId: actionMapfixAccepted
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+        - name: StatusMessage
+          in: query
+          required: true
+          schema:
+            type: string
+            minLength: 0
+            maxLength: 4096
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/validator-uploaded:
+    post:
+      summary: (Internal endpoint) Role Validator changes status from Uploading -> Uploaded
+      operationId: actionMapfixUploaded
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
   /submissions/{SubmissionID}/validated-model:
     post:
       summary: Update validated model
@@ -261,6 +350,14 @@ paths:
                 $ref: "#/components/schemas/Error"
 components:
   parameters:
+    MapfixID:
+      name: MapfixID
+      in: path
+      required: true
+      description: The unique identifier for a submission.
+      schema:
+        type: integer
+        format: int64
     SubmissionID:
       name: SubmissionID
       in: path
diff --git a/openapi.yaml b/openapi.yaml
index 1fdfcea..1f94269 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -6,6 +6,8 @@ info:
 servers:
   - url: https://submissions.strafes.net/v1
 tags:
+  - name: Mapfixes
+    description: Mapfix operations
   - name: Session
     description: Session operations
   - name: Submissions
@@ -74,6 +76,281 @@ paths:
             application/json:
               schema:
                 $ref: "#/components/schemas/Error"
+  /mapfixes:
+    get:
+      summary: Get list of mapfixes
+      operationId: listMapfixes
+      tags:
+        - Mapfixes
+      security: []
+      parameters:
+      - $ref: "#/components/parameters/Page"
+      - $ref: "#/components/parameters/Limit"
+      - name: Sort
+        in: query
+        schema:
+          type: integer
+          format: int32
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Mapfix"
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+    post:
+      summary: Create new mapfix
+      operationId: createMapfix
+      tags:
+        - Mapfixes
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/MapfixCreate'
+      responses:
+        "201":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Id"
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}:
+    get:
+      summary: Retrieve map with ID
+      operationId: getMapfix
+      tags:
+        - Mapfixes
+      security: []
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Mapfix"
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/model:
+    post:
+      summary: Update model following role restrictions
+      operationId: updateMapfixModel
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+        - name: ModelID
+          in: query
+          required: true
+          schema:
+            type: integer
+            format: int64
+        - name: VersionID
+          in: query
+          required: true
+          schema:
+            type: integer
+            format: int64
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/completed:
+    post:
+      summary: Called by maptest when a player completes the map
+      operationId: setMapfixCompleted
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/submit:
+    post:
+      summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
+      operationId: actionMapfixSubmit
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/revoke:
+    post:
+      summary: Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction
+      operationId: actionMapfixRevoke
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/trigger-validate:
+    post:
+      summary: Role Reviewer triggers validation and changes status from Submitted -> Validating
+      operationId: actionMapfixTriggerValidate
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/retry-validate:
+    post:
+      summary: Role Reviewer re-runs validation and changes status from Accepted -> Validating
+      operationId: actionMapfixRetryValidate
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/reset-validating:
+    post:
+      summary: Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted
+      operationId: actionMapfixAccepted
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/reject:
+    post:
+      summary: Role Reviewer changes status from Submitted -> Rejected
+      operationId: actionMapfixReject
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/request-changes:
+    post:
+      summary: Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested
+      operationId: actionMapfixRequestChanges
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/trigger-upload:
+    post:
+      summary: Role Admin changes status from Validated -> Uploading
+      operationId: actionMapfixTriggerUpload
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
+  /mapfixes/{MapfixID}/status/reset-uploading:
+    post:
+      summary: Role Admin manually resets uploading softlock and changes status from Uploading -> Validated
+      operationId: actionMapfixValidated
+      tags:
+        - Mapfixes
+      parameters:
+        - $ref: '#/components/parameters/MapfixID'
+      responses:
+        "204":
+          description: Successful response
+        default:
+          description: General Error
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
   /submissions:
     get:
       summary: Get list of submissions
@@ -656,6 +933,14 @@ components:
       in: cookie
       name: session_id
   parameters:
+    MapfixID:
+      name: MapfixID
+      in: path
+      required: true
+      description: The unique identifier for a mapfix.
+      schema:
+        type: integer
+        format: int64
     SubmissionID:
       name: SubmissionID
       in: path
@@ -730,6 +1015,65 @@ components:
         AvatarURL:
           type: string
           maxLength: 256
+    Mapfix:
+      required:
+      - ID
+      - CreatedAt
+      - UpdatedAt
+      - Submitter
+      - AssetID
+      - AssetVersion
+      - Completed
+      - TargetAssetID
+      - StatusID
+      - StatusMessage
+      type: object
+      properties:
+        ID:
+          type: integer
+          format: int64
+        CreatedAt:
+          type: integer
+          format: int64
+        UpdatedAt:
+          type: integer
+          format: int64
+        Submitter:
+          type: integer
+          format: int64
+        AssetID:
+          type: integer
+          format: int64
+        AssetVersion:
+          type: integer
+          format: int64
+        Completed:
+          type: boolean
+        TargetAssetID:
+          type: integer
+          format: int64
+        StatusID:
+          type: integer
+          format: int32
+        StatusMessage:
+          type: string
+          maxLength: 256
+    MapfixCreate:
+      required:
+      - AssetID
+      - AssetVersion
+      - TargetAssetID
+      type: object
+      properties:
+        AssetID:
+          type: integer
+          format: int64
+        AssetVersion:
+          type: integer
+          format: int64
+        TargetAssetID:
+          type: integer
+          format: int64
     Submission:
       required:
       - ID
-- 
2.47.1


From 6d420c3a827c3c4abda34bc1fa7e5c6509d89bbf Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 31 Mar 2025 16:30:40 -0700
Subject: [PATCH 3/7] openapi: generate

---
 pkg/api/oas_client_gen.go                 | 1799 ++++++++++++++
 pkg/api/oas_handlers_gen.go               | 2654 +++++++++++++++++++++
 pkg/api/oas_json_gen.go                   |  380 +++
 pkg/api/oas_operations_gen.go             |   14 +
 pkg/api/oas_parameters_gen.go             | 1067 +++++++++
 pkg/api/oas_request_decoders_gen.go       |   63 +
 pkg/api/oas_request_encoders_gen.go       |   14 +
 pkg/api/oas_response_decoders_gen.go      |  853 +++++++
 pkg/api/oas_response_encoders_gen.go      |  123 +
 pkg/api/oas_router_gen.go                 |  768 ++++++
 pkg/api/oas_schemas_gen.go                |  184 ++
 pkg/api/oas_server_gen.go                 |   84 +
 pkg/api/oas_unimplemented_gen.go          |  126 +
 pkg/api/oas_validators_gen.go             |   31 +
 pkg/internal/oas_client_gen.go            |  438 ++++
 pkg/internal/oas_handlers_gen.go          |  608 +++++
 pkg/internal/oas_operations_gen.go        |    4 +
 pkg/internal/oas_parameters_gen.go        |  414 ++++
 pkg/internal/oas_response_decoders_gen.go |  204 ++
 pkg/internal/oas_response_encoders_gen.go |   28 +
 pkg/internal/oas_router_gen.go            |  770 ++++--
 pkg/internal/oas_schemas_gen.go           |   12 +
 pkg/internal/oas_server_gen.go            |   24 +
 pkg/internal/oas_unimplemented_gen.go     |   36 +
 24 files changed, 10470 insertions(+), 228 deletions(-)

diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go
index 76746fd..9d04b8b 100644
--- a/pkg/api/oas_client_gen.go
+++ b/pkg/api/oas_client_gen.go
@@ -29,6 +29,60 @@ func trimTrailingSlashes(u *url.URL) {
 
 // Invoker invokes operations described by OpenAPI v3 specification.
 type Invoker interface {
+	// ActionMapfixAccepted invokes actionMapfixAccepted operation.
+	//
+	// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
+	//
+	// POST /mapfixes/{MapfixID}/status/reset-validating
+	ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
+	// ActionMapfixReject invokes actionMapfixReject operation.
+	//
+	// Role Reviewer changes status from Submitted -> Rejected.
+	//
+	// POST /mapfixes/{MapfixID}/status/reject
+	ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error
+	// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
+	//
+	// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+	//
+	// POST /mapfixes/{MapfixID}/status/request-changes
+	ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
+	// ActionMapfixRetryValidate invokes actionMapfixRetryValidate operation.
+	//
+	// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+	//
+	// POST /mapfixes/{MapfixID}/status/retry-validate
+	ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error
+	// ActionMapfixRevoke invokes actionMapfixRevoke operation.
+	//
+	// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+	//
+	// POST /mapfixes/{MapfixID}/status/revoke
+	ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error
+	// ActionMapfixSubmit invokes actionMapfixSubmit operation.
+	//
+	// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+	//
+	// POST /mapfixes/{MapfixID}/status/submit
+	ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error
+	// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
+	//
+	// Role Admin changes status from Validated -> Uploading.
+	//
+	// POST /mapfixes/{MapfixID}/status/trigger-upload
+	ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error
+	// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
+	//
+	// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+	//
+	// POST /mapfixes/{MapfixID}/status/trigger-validate
+	ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error
+	// ActionMapfixValidated invokes actionMapfixValidated operation.
+	//
+	// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
+	//
+	// POST /mapfixes/{MapfixID}/status/reset-uploading
+	ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
 	// ActionSubmissionAccepted invokes actionSubmissionAccepted operation.
 	//
 	// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
@@ -83,6 +137,12 @@ type Invoker interface {
 	//
 	// POST /submissions/{SubmissionID}/status/reset-uploading
 	ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error
+	// CreateMapfix invokes createMapfix operation.
+	//
+	// Create new mapfix.
+	//
+	// POST /mapfixes
+	CreateMapfix(ctx context.Context, request *MapfixCreate) (*ID, error)
 	// CreateScript invokes createScript operation.
 	//
 	// Create a new script.
@@ -113,6 +173,12 @@ type Invoker interface {
 	//
 	// DELETE /script-policy/{ScriptPolicyID}
 	DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error
+	// GetMapfix invokes getMapfix operation.
+	//
+	// Retrieve map with ID.
+	//
+	// GET /mapfixes/{MapfixID}
+	GetMapfix(ctx context.Context, params GetMapfixParams) (*Mapfix, error)
 	// GetScript invokes getScript operation.
 	//
 	// Get the specified script by ID.
@@ -131,6 +197,12 @@ type Invoker interface {
 	//
 	// GET /submissions/{SubmissionID}
 	GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
+	// ListMapfixes invokes listMapfixes operation.
+	//
+	// Get list of mapfixes.
+	//
+	// GET /mapfixes
+	ListMapfixes(ctx context.Context, params ListMapfixesParams) ([]Mapfix, error)
 	// ListScriptPolicy invokes listScriptPolicy operation.
 	//
 	// Get list of script policies.
@@ -173,12 +245,24 @@ type Invoker interface {
 	//
 	// GET /session/validate
 	SessionValidate(ctx context.Context) (bool, error)
+	// SetMapfixCompleted invokes setMapfixCompleted operation.
+	//
+	// Called by maptest when a player completes the map.
+	//
+	// POST /mapfixes/{MapfixID}/completed
+	SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error
 	// SetSubmissionCompleted invokes setSubmissionCompleted operation.
 	//
 	// Called by maptest when a player completes the map.
 	//
 	// POST /submissions/{SubmissionID}/completed
 	SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error
+	// UpdateMapfixModel invokes updateMapfixModel operation.
+	//
+	// Update model following role restrictions.
+	//
+	// POST /mapfixes/{MapfixID}/model
+	UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error
 	// UpdateScript invokes updateScript operation.
 	//
 	// Update the specified script by ID.
@@ -248,6 +332,1122 @@ func (c *Client) requestURL(ctx context.Context) *url.URL {
 	return u
 }
 
+// ActionMapfixAccepted invokes actionMapfixAccepted operation.
+//
+// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/reset-validating
+func (c *Client) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
+	_, err := c.sendActionMapfixAccepted(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) (res *ActionMapfixAcceptedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixAccepted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-validating"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixAcceptedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/reset-validating"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixAcceptedOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixAcceptedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixReject invokes actionMapfixReject operation.
+//
+// Role Reviewer changes status from Submitted -> Rejected.
+//
+// POST /mapfixes/{MapfixID}/status/reject
+func (c *Client) ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error {
+	_, err := c.sendActionMapfixReject(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) (res *ActionMapfixRejectNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixReject"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reject"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixRejectOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/reject"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixRejectOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixRejectResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
+//
+// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+//
+// POST /mapfixes/{MapfixID}/status/request-changes
+func (c *Client) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
+	_, err := c.sendActionMapfixRequestChanges(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) (res *ActionMapfixRequestChangesNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRequestChanges"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/request-changes"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixRequestChangesOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/request-changes"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixRequestChangesOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixRequestChangesResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixRetryValidate invokes actionMapfixRetryValidate operation.
+//
+// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/retry-validate
+func (c *Client) ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error {
+	_, err := c.sendActionMapfixRetryValidate(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) (res *ActionMapfixRetryValidateNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRetryValidate"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/retry-validate"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixRetryValidateOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/retry-validate"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixRetryValidateOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixRetryValidateResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixRevoke invokes actionMapfixRevoke operation.
+//
+// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+//
+// POST /mapfixes/{MapfixID}/status/revoke
+func (c *Client) ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error {
+	_, err := c.sendActionMapfixRevoke(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) (res *ActionMapfixRevokeNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRevoke"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/revoke"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixRevokeOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/revoke"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixRevokeOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixRevokeResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixSubmit invokes actionMapfixSubmit operation.
+//
+// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+//
+// POST /mapfixes/{MapfixID}/status/submit
+func (c *Client) ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error {
+	_, err := c.sendActionMapfixSubmit(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) (res *ActionMapfixSubmitNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixSubmit"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/submit"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixSubmitOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/submit"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixSubmitOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixSubmitResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
+//
+// Role Admin changes status from Validated -> Uploading.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-upload
+func (c *Client) ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error {
+	_, err := c.sendActionMapfixTriggerUpload(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) (res *ActionMapfixTriggerUploadNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixTriggerUpload"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-upload"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixTriggerUploadOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/trigger-upload"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixTriggerUploadOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixTriggerUploadResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
+//
+// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-validate
+func (c *Client) ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error {
+	_, err := c.sendActionMapfixTriggerValidate(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) (res *ActionMapfixTriggerValidateNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixTriggerValidate"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-validate"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixTriggerValidateOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/trigger-validate"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixTriggerValidateOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixTriggerValidateResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixValidated invokes actionMapfixValidated operation.
+//
+// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/reset-uploading
+func (c *Client) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
+	_, err := c.sendActionMapfixValidated(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) (res *ActionMapfixValidatedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixValidated"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-uploading"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixValidatedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/reset-uploading"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, ActionMapfixValidatedOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixValidatedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // ActionSubmissionAccepted invokes actionSubmissionAccepted operation.
 //
 // Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
@@ -1364,6 +2564,114 @@ func (c *Client) sendActionSubmissionValidated(ctx context.Context, params Actio
 	return result, nil
 }
 
+// CreateMapfix invokes createMapfix operation.
+//
+// Create new mapfix.
+//
+// POST /mapfixes
+func (c *Client) CreateMapfix(ctx context.Context, request *MapfixCreate) (*ID, error) {
+	res, err := c.sendCreateMapfix(ctx, request)
+	return res, err
+}
+
+func (c *Client) sendCreateMapfix(ctx context.Context, request *MapfixCreate) (res *ID, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("createMapfix"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, CreateMapfixOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [1]string
+	pathParts[0] = "/mapfixes"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+	if err := encodeCreateMapfixRequest(request, r); err != nil {
+		return res, errors.Wrap(err, "encode request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, CreateMapfixOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeCreateMapfixResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // CreateScript invokes createScript operation.
 //
 // Create a new script.
@@ -1934,6 +3242,96 @@ func (c *Client) sendDeleteScriptPolicy(ctx context.Context, params DeleteScript
 	return result, nil
 }
 
+// GetMapfix invokes getMapfix operation.
+//
+// Retrieve map with ID.
+//
+// GET /mapfixes/{MapfixID}
+func (c *Client) GetMapfix(ctx context.Context, params GetMapfixParams) (*Mapfix, error) {
+	res, err := c.sendGetMapfix(ctx, params)
+	return res, err
+}
+
+func (c *Client) sendGetMapfix(ctx context.Context, params GetMapfixParams) (res *Mapfix, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("getMapfix"),
+		semconv.HTTPRequestMethodKey.String("GET"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, GetMapfixOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [2]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "GET", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeGetMapfixResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // GetScript invokes getScript operation.
 //
 // Get the specified script by ID.
@@ -2204,6 +3602,127 @@ func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionPara
 	return result, nil
 }
 
+// ListMapfixes invokes listMapfixes operation.
+//
+// Get list of mapfixes.
+//
+// GET /mapfixes
+func (c *Client) ListMapfixes(ctx context.Context, params ListMapfixesParams) ([]Mapfix, error) {
+	res, err := c.sendListMapfixes(ctx, params)
+	return res, err
+}
+
+func (c *Client) sendListMapfixes(ctx context.Context, params ListMapfixesParams) (res []Mapfix, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("listMapfixes"),
+		semconv.HTTPRequestMethodKey.String("GET"),
+		semconv.HTTPRouteKey.String("/mapfixes"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ListMapfixesOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [1]string
+	pathParts[0] = "/mapfixes"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeQueryParams"
+	q := uri.NewQueryEncoder()
+	{
+		// Encode "Page" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "Page",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int32ToString(params.Page))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	{
+		// Encode "Limit" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "Limit",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int32ToString(params.Limit))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	{
+		// Encode "Sort" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "Sort",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			if val, ok := params.Sort.Get(); ok {
+				return e.EncodeValue(conv.Int32ToString(val))
+			}
+			return nil
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	u.RawQuery = q.Values().Encode()
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "GET", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeListMapfixesResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // ListScriptPolicy invokes listScriptPolicy operation.
 //
 // Get list of script policies.
@@ -3143,6 +4662,130 @@ func (c *Client) sendSessionValidate(ctx context.Context) (res bool, err error)
 	return result, nil
 }
 
+// SetMapfixCompleted invokes setMapfixCompleted operation.
+//
+// Called by maptest when a player completes the map.
+//
+// POST /mapfixes/{MapfixID}/completed
+func (c *Client) SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error {
+	_, err := c.sendSetMapfixCompleted(ctx, params)
+	return err
+}
+
+func (c *Client) sendSetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) (res *SetMapfixCompletedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("setMapfixCompleted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/completed"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, SetMapfixCompletedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/completed"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, SetMapfixCompletedOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeSetMapfixCompletedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // SetSubmissionCompleted invokes setSubmissionCompleted operation.
 //
 // Called by maptest when a player completes the map.
@@ -3267,6 +4910,162 @@ func (c *Client) sendSetSubmissionCompleted(ctx context.Context, params SetSubmi
 	return result, nil
 }
 
+// UpdateMapfixModel invokes updateMapfixModel operation.
+//
+// Update model following role restrictions.
+//
+// POST /mapfixes/{MapfixID}/model
+func (c *Client) UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error {
+	_, err := c.sendUpdateMapfixModel(ctx, params)
+	return err
+}
+
+func (c *Client) sendUpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) (res *UpdateMapfixModelNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("updateMapfixModel"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/model"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, UpdateMapfixModelOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/model"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeQueryParams"
+	q := uri.NewQueryEncoder()
+	{
+		// Encode "ModelID" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "ModelID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int64ToString(params.ModelID))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	{
+		// Encode "VersionID" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "VersionID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int64ToString(params.VersionID))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	u.RawQuery = q.Values().Encode()
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			stage = "Security:CookieAuth"
+			switch err := c.securityCookieAuth(ctx, UpdateMapfixModelOperation, r); {
+			case err == nil: // if NO error
+				satisfied[0] |= 1 << 0
+			case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+				// Skip this security.
+			default:
+				return res, errors.Wrap(err, "security \"CookieAuth\"")
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+		}
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeUpdateMapfixModelResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // UpdateScript invokes updateScript operation.
 //
 // Update the specified script by ID.
diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go
index 5e41a87..f4005cc 100644
--- a/pkg/api/oas_handlers_gen.go
+++ b/pkg/api/oas_handlers_gen.go
@@ -30,6 +30,1761 @@ func (c *codeRecorder) WriteHeader(status int) {
 	c.ResponseWriter.WriteHeader(status)
 }
 
+// handleActionMapfixAcceptedRequest handles actionMapfixAccepted operation.
+//
+// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/reset-validating
+func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixAccepted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-validating"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixAcceptedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixAcceptedOperation,
+			ID:   "actionMapfixAccepted",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixAcceptedOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixAcceptedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixAcceptedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixAcceptedOperation,
+			OperationSummary: "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted",
+			OperationID:      "actionMapfixAccepted",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixAcceptedParams
+			Response = *ActionMapfixAcceptedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixAcceptedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixAccepted(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixAccepted(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixAcceptedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixRejectRequest handles actionMapfixReject operation.
+//
+// Role Reviewer changes status from Submitted -> Rejected.
+//
+// POST /mapfixes/{MapfixID}/status/reject
+func (s *Server) handleActionMapfixRejectRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixReject"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reject"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRejectOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixRejectOperation,
+			ID:   "actionMapfixReject",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixRejectOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixRejectParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixRejectNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixRejectOperation,
+			OperationSummary: "Role Reviewer changes status from Submitted -> Rejected",
+			OperationID:      "actionMapfixReject",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixRejectParams
+			Response = *ActionMapfixRejectNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixRejectParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixReject(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixReject(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixRejectResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixRequestChangesRequest handles actionMapfixRequestChanges operation.
+//
+// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+//
+// POST /mapfixes/{MapfixID}/status/request-changes
+func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRequestChanges"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/request-changes"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRequestChangesOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixRequestChangesOperation,
+			ID:   "actionMapfixRequestChanges",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixRequestChangesOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixRequestChangesParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixRequestChangesNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixRequestChangesOperation,
+			OperationSummary: "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested",
+			OperationID:      "actionMapfixRequestChanges",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixRequestChangesParams
+			Response = *ActionMapfixRequestChangesNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixRequestChangesParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixRequestChanges(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixRequestChanges(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixRequestChangesResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixRetryValidateRequest handles actionMapfixRetryValidate operation.
+//
+// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/retry-validate
+func (s *Server) handleActionMapfixRetryValidateRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRetryValidate"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/retry-validate"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRetryValidateOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixRetryValidateOperation,
+			ID:   "actionMapfixRetryValidate",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixRetryValidateOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixRetryValidateParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixRetryValidateNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixRetryValidateOperation,
+			OperationSummary: "Role Reviewer re-runs validation and changes status from Accepted -> Validating",
+			OperationID:      "actionMapfixRetryValidate",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixRetryValidateParams
+			Response = *ActionMapfixRetryValidateNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixRetryValidateParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixRetryValidate(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixRetryValidate(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixRetryValidateResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixRevokeRequest handles actionMapfixRevoke operation.
+//
+// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+//
+// POST /mapfixes/{MapfixID}/status/revoke
+func (s *Server) handleActionMapfixRevokeRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixRevoke"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/revoke"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRevokeOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixRevokeOperation,
+			ID:   "actionMapfixRevoke",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixRevokeOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixRevokeParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixRevokeNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixRevokeOperation,
+			OperationSummary: "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction",
+			OperationID:      "actionMapfixRevoke",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixRevokeParams
+			Response = *ActionMapfixRevokeNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixRevokeParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixRevoke(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixRevoke(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixRevokeResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixSubmitRequest handles actionMapfixSubmit operation.
+//
+// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+//
+// POST /mapfixes/{MapfixID}/status/submit
+func (s *Server) handleActionMapfixSubmitRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixSubmit"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/submit"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixSubmitOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixSubmitOperation,
+			ID:   "actionMapfixSubmit",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixSubmitOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixSubmitParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixSubmitNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixSubmitOperation,
+			OperationSummary: "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted",
+			OperationID:      "actionMapfixSubmit",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixSubmitParams
+			Response = *ActionMapfixSubmitNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixSubmitParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixSubmit(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixSubmit(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixSubmitResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixTriggerUploadRequest handles actionMapfixTriggerUpload operation.
+//
+// Role Admin changes status from Validated -> Uploading.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-upload
+func (s *Server) handleActionMapfixTriggerUploadRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixTriggerUpload"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-upload"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerUploadOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixTriggerUploadOperation,
+			ID:   "actionMapfixTriggerUpload",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixTriggerUploadOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixTriggerUploadParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixTriggerUploadNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixTriggerUploadOperation,
+			OperationSummary: "Role Admin changes status from Validated -> Uploading",
+			OperationID:      "actionMapfixTriggerUpload",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixTriggerUploadParams
+			Response = *ActionMapfixTriggerUploadNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixTriggerUploadParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixTriggerUpload(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixTriggerUpload(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixTriggerUploadResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixTriggerValidateRequest handles actionMapfixTriggerValidate operation.
+//
+// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-validate
+func (s *Server) handleActionMapfixTriggerValidateRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixTriggerValidate"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-validate"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerValidateOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixTriggerValidateOperation,
+			ID:   "actionMapfixTriggerValidate",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixTriggerValidateOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixTriggerValidateParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixTriggerValidateNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixTriggerValidateOperation,
+			OperationSummary: "Role Reviewer triggers validation and changes status from Submitted -> Validating",
+			OperationID:      "actionMapfixTriggerValidate",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixTriggerValidateParams
+			Response = *ActionMapfixTriggerValidateNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixTriggerValidateParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixTriggerValidate(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixTriggerValidate(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixTriggerValidateResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixValidatedRequest handles actionMapfixValidated operation.
+//
+// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/reset-uploading
+func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixValidated"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-uploading"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixValidatedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixValidatedOperation,
+			ID:   "actionMapfixValidated",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixValidatedOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeActionMapfixValidatedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixValidatedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixValidatedOperation,
+			OperationSummary: "Role Admin manually resets uploading softlock and changes status from Uploading -> Validated",
+			OperationID:      "actionMapfixValidated",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixValidatedParams
+			Response = *ActionMapfixValidatedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixValidatedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixValidated(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixValidated(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixValidatedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleActionSubmissionAcceptedRequest handles actionSubmissionAccepted operation.
 //
 // Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
@@ -1785,6 +3540,201 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca
 	}
 }
 
+// handleCreateMapfixRequest handles createMapfix operation.
+//
+// Create new mapfix.
+//
+// POST /mapfixes
+func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("createMapfix"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), CreateMapfixOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: CreateMapfixOperation,
+			ID:   "createMapfix",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, CreateMapfixOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	request, close, err := s.decodeCreateMapfixRequest(r)
+	if err != nil {
+		err = &ogenerrors.DecodeRequestError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeRequest", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+	defer func() {
+		if err := close(); err != nil {
+			recordError("CloseRequest", err)
+		}
+	}()
+
+	var response *ID
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    CreateMapfixOperation,
+			OperationSummary: "Create new mapfix",
+			OperationID:      "createMapfix",
+			Body:             request,
+			Params:           middleware.Parameters{},
+			Raw:              r,
+		}
+
+		type (
+			Request  = *MapfixCreate
+			Params   = struct{}
+			Response = *ID
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			nil,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				response, err = s.h.CreateMapfix(ctx, request)
+				return response, err
+			},
+		)
+	} else {
+		response, err = s.h.CreateMapfix(ctx, request)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeCreateMapfixResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleCreateScriptRequest handles createScript operation.
 //
 // Create a new script.
@@ -2760,6 +4710,155 @@ func (s *Server) handleDeleteScriptPolicyRequest(args [1]string, argsEscaped boo
 	}
 }
 
+// handleGetMapfixRequest handles getMapfix operation.
+//
+// Retrieve map with ID.
+//
+// GET /mapfixes/{MapfixID}
+func (s *Server) handleGetMapfixRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("getMapfix"),
+		semconv.HTTPRequestMethodKey.String("GET"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), GetMapfixOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: GetMapfixOperation,
+			ID:   "getMapfix",
+		}
+	)
+	params, err := decodeGetMapfixParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *Mapfix
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    GetMapfixOperation,
+			OperationSummary: "Retrieve map with ID",
+			OperationID:      "getMapfix",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = GetMapfixParams
+			Response = *Mapfix
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackGetMapfixParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				response, err = s.h.GetMapfix(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		response, err = s.h.GetMapfix(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeGetMapfixResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleGetScriptRequest handles getScript operation.
 //
 // Get the specified script by ID.
@@ -3207,6 +5306,163 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w
 	}
 }
 
+// handleListMapfixesRequest handles listMapfixes operation.
+//
+// Get list of mapfixes.
+//
+// GET /mapfixes
+func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("listMapfixes"),
+		semconv.HTTPRequestMethodKey.String("GET"),
+		semconv.HTTPRouteKey.String("/mapfixes"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ListMapfixesOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ListMapfixesOperation,
+			ID:   "listMapfixes",
+		}
+	)
+	params, err := decodeListMapfixesParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response []Mapfix
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ListMapfixesOperation,
+			OperationSummary: "Get list of mapfixes",
+			OperationID:      "listMapfixes",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "Page",
+					In:   "query",
+				}: params.Page,
+				{
+					Name: "Limit",
+					In:   "query",
+				}: params.Limit,
+				{
+					Name: "Sort",
+					In:   "query",
+				}: params.Sort,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ListMapfixesParams
+			Response = []Mapfix
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackListMapfixesParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				response, err = s.h.ListMapfixes(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		response, err = s.h.ListMapfixes(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeListMapfixesResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleListScriptPolicyRequest handles listScriptPolicy operation.
 //
 // Get list of script policies.
@@ -4449,6 +6705,201 @@ func (s *Server) handleSessionValidateRequest(args [0]string, argsEscaped bool,
 	}
 }
 
+// handleSetMapfixCompletedRequest handles setMapfixCompleted operation.
+//
+// Called by maptest when a player completes the map.
+//
+// POST /mapfixes/{MapfixID}/completed
+func (s *Server) handleSetMapfixCompletedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("setMapfixCompleted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/completed"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), SetMapfixCompletedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: SetMapfixCompletedOperation,
+			ID:   "setMapfixCompleted",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, SetMapfixCompletedOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeSetMapfixCompletedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *SetMapfixCompletedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    SetMapfixCompletedOperation,
+			OperationSummary: "Called by maptest when a player completes the map",
+			OperationID:      "setMapfixCompleted",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = SetMapfixCompletedParams
+			Response = *SetMapfixCompletedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackSetMapfixCompletedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.SetMapfixCompleted(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.SetMapfixCompleted(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeSetMapfixCompletedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleSetSubmissionCompletedRequest handles setSubmissionCompleted operation.
 //
 // Called by maptest when a player completes the map.
@@ -4644,6 +7095,209 @@ func (s *Server) handleSetSubmissionCompletedRequest(args [1]string, argsEscaped
 	}
 }
 
+// handleUpdateMapfixModelRequest handles updateMapfixModel operation.
+//
+// Update model following role restrictions.
+//
+// POST /mapfixes/{MapfixID}/model
+func (s *Server) handleUpdateMapfixModelRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("updateMapfixModel"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/model"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateMapfixModelOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: UpdateMapfixModelOperation,
+			ID:   "updateMapfixModel",
+		}
+	)
+	{
+		type bitset = [1]uint8
+		var satisfied bitset
+		{
+			sctx, ok, err := s.securityCookieAuth(ctx, UpdateMapfixModelOperation, r)
+			if err != nil {
+				err = &ogenerrors.SecurityError{
+					OperationContext: opErrContext,
+					Security:         "CookieAuth",
+					Err:              err,
+				}
+				if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+					defer recordError("Security:CookieAuth", err)
+				}
+				return
+			}
+			if ok {
+				satisfied[0] |= 1 << 0
+				ctx = sctx
+			}
+		}
+
+		if ok := func() bool {
+		nextRequirement:
+			for _, requirement := range []bitset{
+				{0b00000001},
+			} {
+				for i, mask := range requirement {
+					if satisfied[i]&mask != mask {
+						continue nextRequirement
+					}
+				}
+				return true
+			}
+			return false
+		}(); !ok {
+			err = &ogenerrors.SecurityError{
+				OperationContext: opErrContext,
+				Err:              ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+			}
+			if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
+				defer recordError("Security", err)
+			}
+			return
+		}
+	}
+	params, err := decodeUpdateMapfixModelParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *UpdateMapfixModelNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    UpdateMapfixModelOperation,
+			OperationSummary: "Update model following role restrictions",
+			OperationID:      "updateMapfixModel",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+				{
+					Name: "ModelID",
+					In:   "query",
+				}: params.ModelID,
+				{
+					Name: "VersionID",
+					In:   "query",
+				}: params.VersionID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = UpdateMapfixModelParams
+			Response = *UpdateMapfixModelNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackUpdateMapfixModelParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.UpdateMapfixModel(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.UpdateMapfixModel(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeUpdateMapfixModelResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleUpdateScriptRequest handles updateScript operation.
 //
 // Update the specified script by ID.
diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go
index bd971cb..c978565 100644
--- a/pkg/api/oas_json_gen.go
+++ b/pkg/api/oas_json_gen.go
@@ -222,6 +222,386 @@ func (s *ID) UnmarshalJSON(data []byte) error {
 	return s.Decode(d)
 }
 
+// Encode implements json.Marshaler.
+func (s *Mapfix) Encode(e *jx.Encoder) {
+	e.ObjStart()
+	s.encodeFields(e)
+	e.ObjEnd()
+}
+
+// encodeFields encodes fields.
+func (s *Mapfix) encodeFields(e *jx.Encoder) {
+	{
+		e.FieldStart("ID")
+		e.Int64(s.ID)
+	}
+	{
+		e.FieldStart("CreatedAt")
+		e.Int64(s.CreatedAt)
+	}
+	{
+		e.FieldStart("UpdatedAt")
+		e.Int64(s.UpdatedAt)
+	}
+	{
+		e.FieldStart("Submitter")
+		e.Int64(s.Submitter)
+	}
+	{
+		e.FieldStart("AssetID")
+		e.Int64(s.AssetID)
+	}
+	{
+		e.FieldStart("AssetVersion")
+		e.Int64(s.AssetVersion)
+	}
+	{
+		e.FieldStart("Completed")
+		e.Bool(s.Completed)
+	}
+	{
+		e.FieldStart("TargetAssetID")
+		e.Int64(s.TargetAssetID)
+	}
+	{
+		e.FieldStart("StatusID")
+		e.Int32(s.StatusID)
+	}
+	{
+		e.FieldStart("StatusMessage")
+		e.Str(s.StatusMessage)
+	}
+}
+
+var jsonFieldsNameOfMapfix = [10]string{
+	0: "ID",
+	1: "CreatedAt",
+	2: "UpdatedAt",
+	3: "Submitter",
+	4: "AssetID",
+	5: "AssetVersion",
+	6: "Completed",
+	7: "TargetAssetID",
+	8: "StatusID",
+	9: "StatusMessage",
+}
+
+// Decode decodes Mapfix from json.
+func (s *Mapfix) Decode(d *jx.Decoder) error {
+	if s == nil {
+		return errors.New("invalid: unable to decode Mapfix to nil")
+	}
+	var requiredBitSet [2]uint8
+
+	if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
+		switch string(k) {
+		case "ID":
+			requiredBitSet[0] |= 1 << 0
+			if err := func() error {
+				v, err := d.Int64()
+				s.ID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ID\"")
+			}
+		case "CreatedAt":
+			requiredBitSet[0] |= 1 << 1
+			if err := func() error {
+				v, err := d.Int64()
+				s.CreatedAt = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"CreatedAt\"")
+			}
+		case "UpdatedAt":
+			requiredBitSet[0] |= 1 << 2
+			if err := func() error {
+				v, err := d.Int64()
+				s.UpdatedAt = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"UpdatedAt\"")
+			}
+		case "Submitter":
+			requiredBitSet[0] |= 1 << 3
+			if err := func() error {
+				v, err := d.Int64()
+				s.Submitter = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"Submitter\"")
+			}
+		case "AssetID":
+			requiredBitSet[0] |= 1 << 4
+			if err := func() error {
+				v, err := d.Int64()
+				s.AssetID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"AssetID\"")
+			}
+		case "AssetVersion":
+			requiredBitSet[0] |= 1 << 5
+			if err := func() error {
+				v, err := d.Int64()
+				s.AssetVersion = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"AssetVersion\"")
+			}
+		case "Completed":
+			requiredBitSet[0] |= 1 << 6
+			if err := func() error {
+				v, err := d.Bool()
+				s.Completed = bool(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"Completed\"")
+			}
+		case "TargetAssetID":
+			requiredBitSet[0] |= 1 << 7
+			if err := func() error {
+				v, err := d.Int64()
+				s.TargetAssetID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"TargetAssetID\"")
+			}
+		case "StatusID":
+			requiredBitSet[1] |= 1 << 0
+			if err := func() error {
+				v, err := d.Int32()
+				s.StatusID = int32(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"StatusID\"")
+			}
+		case "StatusMessage":
+			requiredBitSet[1] |= 1 << 1
+			if err := func() error {
+				v, err := d.Str()
+				s.StatusMessage = string(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"StatusMessage\"")
+			}
+		default:
+			return d.Skip()
+		}
+		return nil
+	}); err != nil {
+		return errors.Wrap(err, "decode Mapfix")
+	}
+	// Validate required fields.
+	var failures []validate.FieldError
+	for i, mask := range [2]uint8{
+		0b11111111,
+		0b00000011,
+	} {
+		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
+			// Mask only required fields and check equality to mask using XOR.
+			//
+			// If XOR result is not zero, result is not equal to expected, so some fields are missed.
+			// Bits of fields which would be set are actually bits of missed fields.
+			missed := bits.OnesCount8(result)
+			for bitN := 0; bitN < missed; bitN++ {
+				bitIdx := bits.TrailingZeros8(result)
+				fieldIdx := i*8 + bitIdx
+				var name string
+				if fieldIdx < len(jsonFieldsNameOfMapfix) {
+					name = jsonFieldsNameOfMapfix[fieldIdx]
+				} else {
+					name = strconv.Itoa(fieldIdx)
+				}
+				failures = append(failures, validate.FieldError{
+					Name:  name,
+					Error: validate.ErrFieldRequired,
+				})
+				// Reset bit.
+				result &^= 1 << bitIdx
+			}
+		}
+	}
+	if len(failures) > 0 {
+		return &validate.Error{Fields: failures}
+	}
+
+	return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *Mapfix) MarshalJSON() ([]byte, error) {
+	e := jx.Encoder{}
+	s.Encode(&e)
+	return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *Mapfix) UnmarshalJSON(data []byte) error {
+	d := jx.DecodeBytes(data)
+	return s.Decode(d)
+}
+
+// Encode implements json.Marshaler.
+func (s *MapfixCreate) Encode(e *jx.Encoder) {
+	e.ObjStart()
+	s.encodeFields(e)
+	e.ObjEnd()
+}
+
+// encodeFields encodes fields.
+func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
+	{
+		e.FieldStart("AssetID")
+		e.Int64(s.AssetID)
+	}
+	{
+		e.FieldStart("AssetVersion")
+		e.Int64(s.AssetVersion)
+	}
+	{
+		e.FieldStart("TargetAssetID")
+		e.Int64(s.TargetAssetID)
+	}
+}
+
+var jsonFieldsNameOfMapfixCreate = [3]string{
+	0: "AssetID",
+	1: "AssetVersion",
+	2: "TargetAssetID",
+}
+
+// Decode decodes MapfixCreate from json.
+func (s *MapfixCreate) Decode(d *jx.Decoder) error {
+	if s == nil {
+		return errors.New("invalid: unable to decode MapfixCreate to nil")
+	}
+	var requiredBitSet [1]uint8
+
+	if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
+		switch string(k) {
+		case "AssetID":
+			requiredBitSet[0] |= 1 << 0
+			if err := func() error {
+				v, err := d.Int64()
+				s.AssetID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"AssetID\"")
+			}
+		case "AssetVersion":
+			requiredBitSet[0] |= 1 << 1
+			if err := func() error {
+				v, err := d.Int64()
+				s.AssetVersion = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"AssetVersion\"")
+			}
+		case "TargetAssetID":
+			requiredBitSet[0] |= 1 << 2
+			if err := func() error {
+				v, err := d.Int64()
+				s.TargetAssetID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"TargetAssetID\"")
+			}
+		default:
+			return d.Skip()
+		}
+		return nil
+	}); err != nil {
+		return errors.Wrap(err, "decode MapfixCreate")
+	}
+	// Validate required fields.
+	var failures []validate.FieldError
+	for i, mask := range [1]uint8{
+		0b00000111,
+	} {
+		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
+			// Mask only required fields and check equality to mask using XOR.
+			//
+			// If XOR result is not zero, result is not equal to expected, so some fields are missed.
+			// Bits of fields which would be set are actually bits of missed fields.
+			missed := bits.OnesCount8(result)
+			for bitN := 0; bitN < missed; bitN++ {
+				bitIdx := bits.TrailingZeros8(result)
+				fieldIdx := i*8 + bitIdx
+				var name string
+				if fieldIdx < len(jsonFieldsNameOfMapfixCreate) {
+					name = jsonFieldsNameOfMapfixCreate[fieldIdx]
+				} else {
+					name = strconv.Itoa(fieldIdx)
+				}
+				failures = append(failures, validate.FieldError{
+					Name:  name,
+					Error: validate.ErrFieldRequired,
+				})
+				// Reset bit.
+				result &^= 1 << bitIdx
+			}
+		}
+	}
+	if len(failures) > 0 {
+		return &validate.Error{Fields: failures}
+	}
+
+	return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *MapfixCreate) MarshalJSON() ([]byte, error) {
+	e := jx.Encoder{}
+	s.Encode(&e)
+	return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *MapfixCreate) UnmarshalJSON(data []byte) error {
+	d := jx.DecodeBytes(data)
+	return s.Decode(d)
+}
+
 // Encode encodes int32 as json.
 func (o OptInt32) Encode(e *jx.Encoder) {
 	if !o.Set {
diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go
index bc77238..04127ea 100644
--- a/pkg/api/oas_operations_gen.go
+++ b/pkg/api/oas_operations_gen.go
@@ -6,6 +6,15 @@ package api
 type OperationName = string
 
 const (
+	ActionMapfixAcceptedOperation            OperationName = "ActionMapfixAccepted"
+	ActionMapfixRejectOperation              OperationName = "ActionMapfixReject"
+	ActionMapfixRequestChangesOperation      OperationName = "ActionMapfixRequestChanges"
+	ActionMapfixRetryValidateOperation       OperationName = "ActionMapfixRetryValidate"
+	ActionMapfixRevokeOperation              OperationName = "ActionMapfixRevoke"
+	ActionMapfixSubmitOperation              OperationName = "ActionMapfixSubmit"
+	ActionMapfixTriggerUploadOperation       OperationName = "ActionMapfixTriggerUpload"
+	ActionMapfixTriggerValidateOperation     OperationName = "ActionMapfixTriggerValidate"
+	ActionMapfixValidatedOperation           OperationName = "ActionMapfixValidated"
 	ActionSubmissionAcceptedOperation        OperationName = "ActionSubmissionAccepted"
 	ActionSubmissionRejectOperation          OperationName = "ActionSubmissionReject"
 	ActionSubmissionRequestChangesOperation  OperationName = "ActionSubmissionRequestChanges"
@@ -15,14 +24,17 @@ const (
 	ActionSubmissionTriggerUploadOperation   OperationName = "ActionSubmissionTriggerUpload"
 	ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
 	ActionSubmissionValidatedOperation       OperationName = "ActionSubmissionValidated"
+	CreateMapfixOperation                    OperationName = "CreateMapfix"
 	CreateScriptOperation                    OperationName = "CreateScript"
 	CreateScriptPolicyOperation              OperationName = "CreateScriptPolicy"
 	CreateSubmissionOperation                OperationName = "CreateSubmission"
 	DeleteScriptOperation                    OperationName = "DeleteScript"
 	DeleteScriptPolicyOperation              OperationName = "DeleteScriptPolicy"
+	GetMapfixOperation                       OperationName = "GetMapfix"
 	GetScriptOperation                       OperationName = "GetScript"
 	GetScriptPolicyOperation                 OperationName = "GetScriptPolicy"
 	GetSubmissionOperation                   OperationName = "GetSubmission"
+	ListMapfixesOperation                    OperationName = "ListMapfixes"
 	ListScriptPolicyOperation                OperationName = "ListScriptPolicy"
 	ListScriptsOperation                     OperationName = "ListScripts"
 	ListSubmissionsOperation                 OperationName = "ListSubmissions"
@@ -30,7 +42,9 @@ const (
 	SessionRolesOperation                    OperationName = "SessionRoles"
 	SessionUserOperation                     OperationName = "SessionUser"
 	SessionValidateOperation                 OperationName = "SessionValidate"
+	SetMapfixCompletedOperation              OperationName = "SetMapfixCompleted"
 	SetSubmissionCompletedOperation          OperationName = "SetSubmissionCompleted"
+	UpdateMapfixModelOperation               OperationName = "UpdateMapfixModel"
 	UpdateScriptOperation                    OperationName = "UpdateScript"
 	UpdateScriptPolicyOperation              OperationName = "UpdateScriptPolicy"
 	UpdateSubmissionModelOperation           OperationName = "UpdateSubmissionModel"
diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go
index d426273..f449071 100644
--- a/pkg/api/oas_parameters_gen.go
+++ b/pkg/api/oas_parameters_gen.go
@@ -15,6 +15,600 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+// ActionMapfixAcceptedParams is parameters of actionMapfixAccepted operation.
+type ActionMapfixAcceptedParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixAcceptedParams(packed middleware.Parameters) (params ActionMapfixAcceptedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixAcceptedParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixRejectParams is parameters of actionMapfixReject operation.
+type ActionMapfixRejectParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixRejectParams(packed middleware.Parameters) (params ActionMapfixRejectParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixRejectParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRejectParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixRequestChangesParams is parameters of actionMapfixRequestChanges operation.
+type ActionMapfixRequestChangesParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixRequestChangesParams(packed middleware.Parameters) (params ActionMapfixRequestChangesParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRequestChangesParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixRetryValidateParams is parameters of actionMapfixRetryValidate operation.
+type ActionMapfixRetryValidateParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixRetryValidateParams(packed middleware.Parameters) (params ActionMapfixRetryValidateParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixRetryValidateParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRetryValidateParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixRevokeParams is parameters of actionMapfixRevoke operation.
+type ActionMapfixRevokeParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixRevokeParams(packed middleware.Parameters) (params ActionMapfixRevokeParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixRevokeParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRevokeParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixSubmitParams is parameters of actionMapfixSubmit operation.
+type ActionMapfixSubmitParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixSubmitParams(packed middleware.Parameters) (params ActionMapfixSubmitParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixSubmitParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixSubmitParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixTriggerUploadParams is parameters of actionMapfixTriggerUpload operation.
+type ActionMapfixTriggerUploadParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixTriggerUploadParams(packed middleware.Parameters) (params ActionMapfixTriggerUploadParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixTriggerUploadParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixTriggerUploadParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixTriggerValidateParams is parameters of actionMapfixTriggerValidate operation.
+type ActionMapfixTriggerValidateParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixTriggerValidateParams(packed middleware.Parameters) (params ActionMapfixTriggerValidateParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixTriggerValidateParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixTriggerValidateParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixValidatedParams is parameters of actionMapfixValidated operation.
+type ActionMapfixValidatedParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackActionMapfixValidatedParams(packed middleware.Parameters) (params ActionMapfixValidatedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixValidatedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixValidatedParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // ActionSubmissionAcceptedParams is parameters of actionSubmissionAccepted operation.
 type ActionSubmissionAcceptedParams struct {
 	// The unique identifier for a submission.
@@ -741,6 +1335,72 @@ func decodeDeleteScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Re
 	return params, nil
 }
 
+// GetMapfixParams is parameters of getMapfix operation.
+type GetMapfixParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackGetMapfixParams(packed middleware.Parameters) (params GetMapfixParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeGetMapfixParams(args [1]string, argsEscaped bool, r *http.Request) (params GetMapfixParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // GetScriptParams is parameters of getScript operation.
 type GetScriptParams struct {
 	// The unique identifier for a script.
@@ -939,6 +1599,192 @@ func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request
 	return params, nil
 }
 
+// ListMapfixesParams is parameters of listMapfixes operation.
+type ListMapfixesParams struct {
+	Page  int32
+	Limit int32
+	Sort  OptInt32
+}
+
+func unpackListMapfixesParams(packed middleware.Parameters) (params ListMapfixesParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "Page",
+			In:   "query",
+		}
+		params.Page = packed[key].(int32)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "Limit",
+			In:   "query",
+		}
+		params.Limit = packed[key].(int32)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "Sort",
+			In:   "query",
+		}
+		if v, ok := packed[key]; ok {
+			params.Sort = v.(OptInt32)
+		}
+	}
+	return params
+}
+
+func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) (params ListMapfixesParams, _ error) {
+	q := uri.NewQueryDecoder(r.URL.Query())
+	// Decode query: Page.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "Page",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt32(val)
+				if err != nil {
+					return err
+				}
+
+				params.Page = c
+				return nil
+			}); err != nil {
+				return err
+			}
+			if err := func() error {
+				if err := (validate.Int{
+					MinSet:        true,
+					Min:           1,
+					MaxSet:        false,
+					Max:           0,
+					MinExclusive:  false,
+					MaxExclusive:  false,
+					MultipleOfSet: false,
+					MultipleOf:    0,
+				}).Validate(int64(params.Page)); err != nil {
+					return errors.Wrap(err, "int")
+				}
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "Page",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	// Decode query: Limit.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "Limit",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt32(val)
+				if err != nil {
+					return err
+				}
+
+				params.Limit = c
+				return nil
+			}); err != nil {
+				return err
+			}
+			if err := func() error {
+				if err := (validate.Int{
+					MinSet:        true,
+					Min:           1,
+					MaxSet:        true,
+					Max:           100,
+					MinExclusive:  false,
+					MaxExclusive:  false,
+					MultipleOfSet: false,
+					MultipleOf:    0,
+				}).Validate(int64(params.Limit)); err != nil {
+					return errors.Wrap(err, "int")
+				}
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "Limit",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	// Decode query: Sort.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "Sort",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				var paramsDotSortVal int32
+				if err := func() error {
+					val, err := d.DecodeValue()
+					if err != nil {
+						return err
+					}
+
+					c, err := conv.ToInt32(val)
+					if err != nil {
+						return err
+					}
+
+					paramsDotSortVal = c
+					return nil
+				}(); err != nil {
+					return err
+				}
+				params.Sort.SetTo(paramsDotSortVal)
+				return nil
+			}); err != nil {
+				return err
+			}
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "Sort",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // ListScriptPolicyParams is parameters of listScriptPolicy operation.
 type ListScriptPolicyParams struct {
 	Page           int32
@@ -2094,6 +2940,72 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque
 	return params, nil
 }
 
+// SetMapfixCompletedParams is parameters of setMapfixCompleted operation.
+type SetMapfixCompletedParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID int64
+}
+
+func unpackSetMapfixCompletedParams(packed middleware.Parameters) (params SetMapfixCompletedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeSetMapfixCompletedParams(args [1]string, argsEscaped bool, r *http.Request) (params SetMapfixCompletedParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // SetSubmissionCompletedParams is parameters of setSubmissionCompleted operation.
 type SetSubmissionCompletedParams struct {
 	// The unique identifier for a submission.
@@ -2160,6 +3072,161 @@ func decodeSetSubmissionCompletedParams(args [1]string, argsEscaped bool, r *htt
 	return params, nil
 }
 
+// UpdateMapfixModelParams is parameters of updateMapfixModel operation.
+type UpdateMapfixModelParams struct {
+	// The unique identifier for a mapfix.
+	MapfixID  int64
+	ModelID   int64
+	VersionID int64
+}
+
+func unpackUpdateMapfixModelParams(packed middleware.Parameters) (params UpdateMapfixModelParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "ModelID",
+			In:   "query",
+		}
+		params.ModelID = packed[key].(int64)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "VersionID",
+			In:   "query",
+		}
+		params.VersionID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeUpdateMapfixModelParams(args [1]string, argsEscaped bool, r *http.Request) (params UpdateMapfixModelParams, _ error) {
+	q := uri.NewQueryDecoder(r.URL.Query())
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	// Decode query: ModelID.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "ModelID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.ModelID = c
+				return nil
+			}); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "ModelID",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	// Decode query: VersionID.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "VersionID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.VersionID = c
+				return nil
+			}); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "VersionID",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // UpdateScriptParams is parameters of updateScript operation.
 type UpdateScriptParams struct {
 	// The unique identifier for a script.
diff --git a/pkg/api/oas_request_decoders_gen.go b/pkg/api/oas_request_decoders_gen.go
index 21dcbd8..e188162 100644
--- a/pkg/api/oas_request_decoders_gen.go
+++ b/pkg/api/oas_request_decoders_gen.go
@@ -15,6 +15,69 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
+	req *MapfixCreate,
+	close func() error,
+	rerr error,
+) {
+	var closers []func() error
+	close = func() error {
+		var merr error
+		// Close in reverse order, to match defer behavior.
+		for i := len(closers) - 1; i >= 0; i-- {
+			c := closers[i]
+			merr = multierr.Append(merr, c())
+		}
+		return merr
+	}
+	defer func() {
+		if rerr != nil {
+			rerr = multierr.Append(rerr, close())
+		}
+	}()
+	ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
+	if err != nil {
+		return req, close, errors.Wrap(err, "parse media type")
+	}
+	switch {
+	case ct == "application/json":
+		if r.ContentLength == 0 {
+			return req, close, validate.ErrBodyRequired
+		}
+		buf, err := io.ReadAll(r.Body)
+		if err != nil {
+			return req, close, err
+		}
+
+		if len(buf) == 0 {
+			return req, close, validate.ErrBodyRequired
+		}
+
+		d := jx.DecodeBytes(buf)
+
+		var request MapfixCreate
+		if err := func() error {
+			if err := request.Decode(d); err != nil {
+				return err
+			}
+			if err := d.Skip(); err != io.EOF {
+				return errors.New("unexpected trailing data")
+			}
+			return nil
+		}(); err != nil {
+			err = &ogenerrors.DecodeBodyError{
+				ContentType: ct,
+				Body:        buf,
+				Err:         err,
+			}
+			return req, close, err
+		}
+		return &request, close, nil
+	default:
+		return req, close, validate.InvalidContentType(ct)
+	}
+}
+
 func (s *Server) decodeCreateScriptRequest(r *http.Request) (
 	req *ScriptCreate,
 	close func() error,
diff --git a/pkg/api/oas_request_encoders_gen.go b/pkg/api/oas_request_encoders_gen.go
index 3a0ac47..b8686b0 100644
--- a/pkg/api/oas_request_encoders_gen.go
+++ b/pkg/api/oas_request_encoders_gen.go
@@ -11,6 +11,20 @@ import (
 	ht "github.com/ogen-go/ogen/http"
 )
 
+func encodeCreateMapfixRequest(
+	req *MapfixCreate,
+	r *http.Request,
+) error {
+	const contentType = "application/json"
+	e := new(jx.Encoder)
+	{
+		req.Encode(e)
+	}
+	encoded := e.Bytes()
+	ht.SetBody(r, bytes.NewReader(encoded), contentType)
+	return nil
+}
+
 func encodeCreateScriptRequest(
 	req *ScriptCreate,
 	r *http.Request,
diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go
index cacfcbe..828a516 100644
--- a/pkg/api/oas_response_decoders_gen.go
+++ b/pkg/api/oas_response_decoders_gen.go
@@ -15,6 +15,465 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixAcceptedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixAcceptedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixRejectResponse(resp *http.Response) (res *ActionMapfixRejectNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixRejectNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixRequestChangesResponse(resp *http.Response) (res *ActionMapfixRequestChangesNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixRequestChangesNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixRetryValidateResponse(resp *http.Response) (res *ActionMapfixRetryValidateNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixRetryValidateNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixRevokeResponse(resp *http.Response) (res *ActionMapfixRevokeNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixRevokeNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixSubmitResponse(resp *http.Response) (res *ActionMapfixSubmitNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixSubmitNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixTriggerUploadResponse(resp *http.Response) (res *ActionMapfixTriggerUploadNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixTriggerUploadNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixTriggerValidateResponse(resp *http.Response) (res *ActionMapfixTriggerValidateNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixTriggerValidateNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixValidatedResponse(resp *http.Response) (res *ActionMapfixValidatedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixValidatedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSubmissionAcceptedNoContent, _ error) {
 	switch resp.StatusCode {
 	case 204:
@@ -474,6 +933,89 @@ func decodeActionSubmissionValidatedResponse(resp *http.Response) (res *ActionSu
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeCreateMapfixResponse(resp *http.Response) (res *ID, _ error) {
+	switch resp.StatusCode {
+	case 201:
+		// Code 201.
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response ID
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &response, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeCreateScriptResponse(resp *http.Response) (res *ID, _ error) {
 	switch resp.StatusCode {
 	case 201:
@@ -825,6 +1367,98 @@ func decodeDeleteScriptPolicyResponse(resp *http.Response) (res *DeleteScriptPol
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeGetMapfixResponse(resp *http.Response) (res *Mapfix, _ error) {
+	switch resp.StatusCode {
+	case 200:
+		// Code 200.
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Mapfix
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			// Validate response.
+			if err := func() error {
+				if err := response.Validate(); err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return res, errors.Wrap(err, "validate")
+			}
+			return &response, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeGetScriptResponse(resp *http.Response) (res *Script, _ error) {
 	switch resp.StatusCode {
 	case 200:
@@ -1101,6 +1735,123 @@ func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error)
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeListMapfixesResponse(resp *http.Response) (res []Mapfix, _ error) {
+	switch resp.StatusCode {
+	case 200:
+		// Code 200.
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response []Mapfix
+			if err := func() error {
+				response = make([]Mapfix, 0)
+				if err := d.Arr(func(d *jx.Decoder) error {
+					var elem Mapfix
+					if err := elem.Decode(d); err != nil {
+						return err
+					}
+					response = append(response, elem)
+					return nil
+				}); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			// Validate response.
+			if err := func() error {
+				if response == nil {
+					return errors.New("nil is invalid value")
+				}
+				var failures []validate.FieldError
+				for i, elem := range response {
+					if err := func() error {
+						if err := elem.Validate(); err != nil {
+							return err
+						}
+						return nil
+					}(); err != nil {
+						failures = append(failures, validate.FieldError{
+							Name:  fmt.Sprintf("[%d]", i),
+							Error: err,
+						})
+					}
+				}
+				if len(failures) > 0 {
+					return &validate.Error{Fields: failures}
+				}
+				return nil
+			}(); err != nil {
+				return res, errors.Wrap(err, "validate")
+			}
+			return response, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeListScriptPolicyResponse(resp *http.Response) (res []ScriptPolicy, _ error) {
 	switch resp.StatusCode {
 	case 200:
@@ -1763,6 +2514,57 @@ func decodeSessionValidateResponse(resp *http.Response) (res bool, _ error) {
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeSetMapfixCompletedResponse(resp *http.Response) (res *SetMapfixCompletedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &SetMapfixCompletedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeSetSubmissionCompletedResponse(resp *http.Response) (res *SetSubmissionCompletedNoContent, _ error) {
 	switch resp.StatusCode {
 	case 204:
@@ -1814,6 +2616,57 @@ func decodeSetSubmissionCompletedResponse(resp *http.Response) (res *SetSubmissi
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeUpdateMapfixModelResponse(resp *http.Response) (res *UpdateMapfixModelNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &UpdateMapfixModelNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeUpdateScriptResponse(resp *http.Response) (res *UpdateScriptNoContent, _ error) {
 	switch resp.StatusCode {
 	case 204:
diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go
index 7a79958..692f548 100644
--- a/pkg/api/oas_response_encoders_gen.go
+++ b/pkg/api/oas_response_encoders_gen.go
@@ -13,6 +13,69 @@ import (
 	ht "github.com/ogen-go/ogen/http"
 )
 
+func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixRejectResponse(response *ActionMapfixRejectNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixRetryValidateResponse(response *ActionMapfixRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixRevokeResponse(response *ActionMapfixRevokeNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixSubmitResponse(response *ActionMapfixSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixTriggerUploadResponse(response *ActionMapfixTriggerUploadNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixTriggerValidateResponse(response *ActionMapfixTriggerValidateNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixValidatedResponse(response *ActionMapfixValidatedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
 func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
 	w.WriteHeader(204)
 	span.SetStatus(codes.Ok, http.StatusText(204))
@@ -76,6 +139,20 @@ func encodeActionSubmissionValidatedResponse(response *ActionSubmissionValidated
 	return nil
 }
 
+func encodeCreateMapfixResponse(response *ID, w http.ResponseWriter, span trace.Span) error {
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	w.WriteHeader(201)
+	span.SetStatus(codes.Ok, http.StatusText(201))
+
+	e := new(jx.Encoder)
+	response.Encode(e)
+	if _, err := e.WriteTo(w); err != nil {
+		return errors.Wrap(err, "write")
+	}
+
+	return nil
+}
+
 func encodeCreateScriptResponse(response *ID, w http.ResponseWriter, span trace.Span) error {
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 	w.WriteHeader(201)
@@ -132,6 +209,20 @@ func encodeDeleteScriptPolicyResponse(response *DeleteScriptPolicyNoContent, w h
 	return nil
 }
 
+func encodeGetMapfixResponse(response *Mapfix, w http.ResponseWriter, span trace.Span) error {
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	w.WriteHeader(200)
+	span.SetStatus(codes.Ok, http.StatusText(200))
+
+	e := new(jx.Encoder)
+	response.Encode(e)
+	if _, err := e.WriteTo(w); err != nil {
+		return errors.Wrap(err, "write")
+	}
+
+	return nil
+}
+
 func encodeGetScriptResponse(response *Script, w http.ResponseWriter, span trace.Span) error {
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 	w.WriteHeader(200)
@@ -174,6 +265,24 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp
 	return nil
 }
 
+func encodeListMapfixesResponse(response []Mapfix, w http.ResponseWriter, span trace.Span) error {
+	w.Header().Set("Content-Type", "application/json; charset=utf-8")
+	w.WriteHeader(200)
+	span.SetStatus(codes.Ok, http.StatusText(200))
+
+	e := new(jx.Encoder)
+	e.ArrStart()
+	for _, elem := range response {
+		elem.Encode(e)
+	}
+	e.ArrEnd()
+	if _, err := e.WriteTo(w); err != nil {
+		return errors.Wrap(err, "write")
+	}
+
+	return nil
+}
+
 func encodeListScriptPolicyResponse(response []ScriptPolicy, w http.ResponseWriter, span trace.Span) error {
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 	w.WriteHeader(200)
@@ -277,6 +386,13 @@ func encodeSessionValidateResponse(response bool, w http.ResponseWriter, span tr
 	return nil
 }
 
+func encodeSetMapfixCompletedResponse(response *SetMapfixCompletedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
 func encodeSetSubmissionCompletedResponse(response *SetSubmissionCompletedNoContent, w http.ResponseWriter, span trace.Span) error {
 	w.WriteHeader(204)
 	span.SetStatus(codes.Ok, http.StatusText(204))
@@ -284,6 +400,13 @@ func encodeSetSubmissionCompletedResponse(response *SetSubmissionCompletedNoCont
 	return nil
 }
 
+func encodeUpdateMapfixModelResponse(response *UpdateMapfixModelNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
 func encodeUpdateScriptResponse(response *UpdateScriptNoContent, w http.ResponseWriter, span trace.Span) error {
 	w.WriteHeader(204)
 	span.SetStatus(codes.Ok, http.StatusText(204))
diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go
index feac3c9..fb0e008 100644
--- a/pkg/api/oas_router_gen.go
+++ b/pkg/api/oas_router_gen.go
@@ -61,6 +61,373 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 				break
 			}
 			switch elem[0] {
+			case 'm': // Prefix: "mapfixes"
+
+				if l := len("mapfixes"); len(elem) >= l && elem[0:l] == "mapfixes" {
+					elem = elem[l:]
+				} else {
+					break
+				}
+
+				if len(elem) == 0 {
+					switch r.Method {
+					case "GET":
+						s.handleListMapfixesRequest([0]string{}, elemIsEscaped, w, r)
+					case "POST":
+						s.handleCreateMapfixRequest([0]string{}, elemIsEscaped, w, r)
+					default:
+						s.notAllowed(w, r, "GET,POST")
+					}
+
+					return
+				}
+				switch elem[0] {
+				case '/': // Prefix: "/"
+
+					if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					// Param: "MapfixID"
+					// Match until "/"
+					idx := strings.IndexByte(elem, '/')
+					if idx < 0 {
+						idx = len(elem)
+					}
+					args[0] = elem[:idx]
+					elem = elem[idx:]
+
+					if len(elem) == 0 {
+						switch r.Method {
+						case "GET":
+							s.handleGetMapfixRequest([1]string{
+								args[0],
+							}, elemIsEscaped, w, r)
+						default:
+							s.notAllowed(w, r, "GET")
+						}
+
+						return
+					}
+					switch elem[0] {
+					case '/': // Prefix: "/"
+
+						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							break
+						}
+						switch elem[0] {
+						case 'c': // Prefix: "completed"
+
+							if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch r.Method {
+								case "POST":
+									s.handleSetMapfixCompletedRequest([1]string{
+										args[0],
+									}, elemIsEscaped, w, r)
+								default:
+									s.notAllowed(w, r, "POST")
+								}
+
+								return
+							}
+
+						case 'm': // Prefix: "model"
+
+							if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch r.Method {
+								case "POST":
+									s.handleUpdateMapfixModelRequest([1]string{
+										args[0],
+									}, elemIsEscaped, w, r)
+								default:
+									s.notAllowed(w, r, "POST")
+								}
+
+								return
+							}
+
+						case 's': // Prefix: "status/"
+
+							if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								break
+							}
+							switch elem[0] {
+							case 'r': // Prefix: "re"
+
+								if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									break
+								}
+								switch elem[0] {
+								case 'j': // Prefix: "ject"
+
+									if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixRejectRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								case 'q': // Prefix: "quest-changes"
+
+									if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixRequestChangesRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								case 's': // Prefix: "set-"
+
+									if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										break
+									}
+									switch elem[0] {
+									case 'u': // Prefix: "uploading"
+
+										if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
+											elem = elem[l:]
+										} else {
+											break
+										}
+
+										if len(elem) == 0 {
+											// Leaf node.
+											switch r.Method {
+											case "POST":
+												s.handleActionMapfixValidatedRequest([1]string{
+													args[0],
+												}, elemIsEscaped, w, r)
+											default:
+												s.notAllowed(w, r, "POST")
+											}
+
+											return
+										}
+
+									case 'v': // Prefix: "validating"
+
+										if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" {
+											elem = elem[l:]
+										} else {
+											break
+										}
+
+										if len(elem) == 0 {
+											// Leaf node.
+											switch r.Method {
+											case "POST":
+												s.handleActionMapfixAcceptedRequest([1]string{
+													args[0],
+												}, elemIsEscaped, w, r)
+											default:
+												s.notAllowed(w, r, "POST")
+											}
+
+											return
+										}
+
+									}
+
+								case 't': // Prefix: "try-validate"
+
+									if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixRetryValidateRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								case 'v': // Prefix: "voke"
+
+									if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixRevokeRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								}
+
+							case 's': // Prefix: "submit"
+
+								if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch r.Method {
+									case "POST":
+										s.handleActionMapfixSubmitRequest([1]string{
+											args[0],
+										}, elemIsEscaped, w, r)
+									default:
+										s.notAllowed(w, r, "POST")
+									}
+
+									return
+								}
+
+							case 't': // Prefix: "trigger-"
+
+								if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									break
+								}
+								switch elem[0] {
+								case 'u': // Prefix: "upload"
+
+									if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixTriggerUploadRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								case 'v': // Prefix: "validate"
+
+									if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch r.Method {
+										case "POST":
+											s.handleActionMapfixTriggerValidateRequest([1]string{
+												args[0],
+											}, elemIsEscaped, w, r)
+										default:
+											s.notAllowed(w, r, "POST")
+										}
+
+										return
+									}
+
+								}
+
+							}
+
+						}
+
+					}
+
+				}
+
 			case 'r': // Prefix: "release-submissions"
 
 				if l := len("release-submissions"); len(elem) >= l && elem[0:l] == "release-submissions" {
@@ -768,6 +1135,407 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 				break
 			}
 			switch elem[0] {
+			case 'm': // Prefix: "mapfixes"
+
+				if l := len("mapfixes"); len(elem) >= l && elem[0:l] == "mapfixes" {
+					elem = elem[l:]
+				} else {
+					break
+				}
+
+				if len(elem) == 0 {
+					switch method {
+					case "GET":
+						r.name = ListMapfixesOperation
+						r.summary = "Get list of mapfixes"
+						r.operationID = "listMapfixes"
+						r.pathPattern = "/mapfixes"
+						r.args = args
+						r.count = 0
+						return r, true
+					case "POST":
+						r.name = CreateMapfixOperation
+						r.summary = "Create new mapfix"
+						r.operationID = "createMapfix"
+						r.pathPattern = "/mapfixes"
+						r.args = args
+						r.count = 0
+						return r, true
+					default:
+						return
+					}
+				}
+				switch elem[0] {
+				case '/': // Prefix: "/"
+
+					if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					// Param: "MapfixID"
+					// Match until "/"
+					idx := strings.IndexByte(elem, '/')
+					if idx < 0 {
+						idx = len(elem)
+					}
+					args[0] = elem[:idx]
+					elem = elem[idx:]
+
+					if len(elem) == 0 {
+						switch method {
+						case "GET":
+							r.name = GetMapfixOperation
+							r.summary = "Retrieve map with ID"
+							r.operationID = "getMapfix"
+							r.pathPattern = "/mapfixes/{MapfixID}"
+							r.args = args
+							r.count = 1
+							return r, true
+						default:
+							return
+						}
+					}
+					switch elem[0] {
+					case '/': // Prefix: "/"
+
+						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							break
+						}
+						switch elem[0] {
+						case 'c': // Prefix: "completed"
+
+							if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch method {
+								case "POST":
+									r.name = SetMapfixCompletedOperation
+									r.summary = "Called by maptest when a player completes the map"
+									r.operationID = "setMapfixCompleted"
+									r.pathPattern = "/mapfixes/{MapfixID}/completed"
+									r.args = args
+									r.count = 1
+									return r, true
+								default:
+									return
+								}
+							}
+
+						case 'm': // Prefix: "model"
+
+							if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch method {
+								case "POST":
+									r.name = UpdateMapfixModelOperation
+									r.summary = "Update model following role restrictions"
+									r.operationID = "updateMapfixModel"
+									r.pathPattern = "/mapfixes/{MapfixID}/model"
+									r.args = args
+									r.count = 1
+									return r, true
+								default:
+									return
+								}
+							}
+
+						case 's': // Prefix: "status/"
+
+							if l := len("status/"); len(elem) >= l && elem[0:l] == "status/" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								break
+							}
+							switch elem[0] {
+							case 'r': // Prefix: "re"
+
+								if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									break
+								}
+								switch elem[0] {
+								case 'j': // Prefix: "ject"
+
+									if l := len("ject"); len(elem) >= l && elem[0:l] == "ject" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixRejectOperation
+											r.summary = "Role Reviewer changes status from Submitted -> Rejected"
+											r.operationID = "actionMapfixReject"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/reject"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								case 'q': // Prefix: "quest-changes"
+
+									if l := len("quest-changes"); len(elem) >= l && elem[0:l] == "quest-changes" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixRequestChangesOperation
+											r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested"
+											r.operationID = "actionMapfixRequestChanges"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/request-changes"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								case 's': // Prefix: "set-"
+
+									if l := len("set-"); len(elem) >= l && elem[0:l] == "set-" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										break
+									}
+									switch elem[0] {
+									case 'u': // Prefix: "uploading"
+
+										if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
+											elem = elem[l:]
+										} else {
+											break
+										}
+
+										if len(elem) == 0 {
+											// Leaf node.
+											switch method {
+											case "POST":
+												r.name = ActionMapfixValidatedOperation
+												r.summary = "Role Admin manually resets uploading softlock and changes status from Uploading -> Validated"
+												r.operationID = "actionMapfixValidated"
+												r.pathPattern = "/mapfixes/{MapfixID}/status/reset-uploading"
+												r.args = args
+												r.count = 1
+												return r, true
+											default:
+												return
+											}
+										}
+
+									case 'v': // Prefix: "validating"
+
+										if l := len("validating"); len(elem) >= l && elem[0:l] == "validating" {
+											elem = elem[l:]
+										} else {
+											break
+										}
+
+										if len(elem) == 0 {
+											// Leaf node.
+											switch method {
+											case "POST":
+												r.name = ActionMapfixAcceptedOperation
+												r.summary = "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted"
+												r.operationID = "actionMapfixAccepted"
+												r.pathPattern = "/mapfixes/{MapfixID}/status/reset-validating"
+												r.args = args
+												r.count = 1
+												return r, true
+											default:
+												return
+											}
+										}
+
+									}
+
+								case 't': // Prefix: "try-validate"
+
+									if l := len("try-validate"); len(elem) >= l && elem[0:l] == "try-validate" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixRetryValidateOperation
+											r.summary = "Role Reviewer re-runs validation and changes status from Accepted -> Validating"
+											r.operationID = "actionMapfixRetryValidate"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/retry-validate"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								case 'v': // Prefix: "voke"
+
+									if l := len("voke"); len(elem) >= l && elem[0:l] == "voke" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixRevokeOperation
+											r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction"
+											r.operationID = "actionMapfixRevoke"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/revoke"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								}
+
+							case 's': // Prefix: "submit"
+
+								if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch method {
+									case "POST":
+										r.name = ActionMapfixSubmitOperation
+										r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
+										r.operationID = "actionMapfixSubmit"
+										r.pathPattern = "/mapfixes/{MapfixID}/status/submit"
+										r.args = args
+										r.count = 1
+										return r, true
+									default:
+										return
+									}
+								}
+
+							case 't': // Prefix: "trigger-"
+
+								if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									break
+								}
+								switch elem[0] {
+								case 'u': // Prefix: "upload"
+
+									if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixTriggerUploadOperation
+											r.summary = "Role Admin changes status from Validated -> Uploading"
+											r.operationID = "actionMapfixTriggerUpload"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-upload"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								case 'v': // Prefix: "validate"
+
+									if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" {
+										elem = elem[l:]
+									} else {
+										break
+									}
+
+									if len(elem) == 0 {
+										// Leaf node.
+										switch method {
+										case "POST":
+											r.name = ActionMapfixTriggerValidateOperation
+											r.summary = "Role Reviewer triggers validation and changes status from Submitted -> Validating"
+											r.operationID = "actionMapfixTriggerValidate"
+											r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-validate"
+											r.args = args
+											r.count = 1
+											return r, true
+										default:
+											return
+										}
+									}
+
+								}
+
+							}
+
+						}
+
+					}
+
+				}
+
 			case 'r': // Prefix: "release-submissions"
 
 				if l := len("release-submissions"); len(elem) >= l && elem[0:l] == "release-submissions" {
diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go
index 83270eb..cc85ff0 100644
--- a/pkg/api/oas_schemas_gen.go
+++ b/pkg/api/oas_schemas_gen.go
@@ -11,6 +11,33 @@ func (s *ErrorStatusCode) Error() string {
 	return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response)
 }
 
+// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
+type ActionMapfixAcceptedNoContent struct{}
+
+// ActionMapfixRejectNoContent is response for ActionMapfixReject operation.
+type ActionMapfixRejectNoContent struct{}
+
+// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
+type ActionMapfixRequestChangesNoContent struct{}
+
+// ActionMapfixRetryValidateNoContent is response for ActionMapfixRetryValidate operation.
+type ActionMapfixRetryValidateNoContent struct{}
+
+// ActionMapfixRevokeNoContent is response for ActionMapfixRevoke operation.
+type ActionMapfixRevokeNoContent struct{}
+
+// ActionMapfixSubmitNoContent is response for ActionMapfixSubmit operation.
+type ActionMapfixSubmitNoContent struct{}
+
+// ActionMapfixTriggerUploadNoContent is response for ActionMapfixTriggerUpload operation.
+type ActionMapfixTriggerUploadNoContent struct{}
+
+// ActionMapfixTriggerValidateNoContent is response for ActionMapfixTriggerValidate operation.
+type ActionMapfixTriggerValidateNoContent struct{}
+
+// ActionMapfixValidatedNoContent is response for ActionMapfixValidated operation.
+type ActionMapfixValidatedNoContent struct{}
+
 // ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
 type ActionSubmissionAcceptedNoContent struct{}
 
@@ -126,6 +153,157 @@ func (s *ID) SetID(val int64) {
 	s.ID = val
 }
 
+// Ref: #/components/schemas/Mapfix
+type Mapfix struct {
+	ID            int64  `json:"ID"`
+	CreatedAt     int64  `json:"CreatedAt"`
+	UpdatedAt     int64  `json:"UpdatedAt"`
+	Submitter     int64  `json:"Submitter"`
+	AssetID       int64  `json:"AssetID"`
+	AssetVersion  int64  `json:"AssetVersion"`
+	Completed     bool   `json:"Completed"`
+	TargetAssetID int64  `json:"TargetAssetID"`
+	StatusID      int32  `json:"StatusID"`
+	StatusMessage string `json:"StatusMessage"`
+}
+
+// GetID returns the value of ID.
+func (s *Mapfix) GetID() int64 {
+	return s.ID
+}
+
+// GetCreatedAt returns the value of CreatedAt.
+func (s *Mapfix) GetCreatedAt() int64 {
+	return s.CreatedAt
+}
+
+// GetUpdatedAt returns the value of UpdatedAt.
+func (s *Mapfix) GetUpdatedAt() int64 {
+	return s.UpdatedAt
+}
+
+// GetSubmitter returns the value of Submitter.
+func (s *Mapfix) GetSubmitter() int64 {
+	return s.Submitter
+}
+
+// GetAssetID returns the value of AssetID.
+func (s *Mapfix) GetAssetID() int64 {
+	return s.AssetID
+}
+
+// GetAssetVersion returns the value of AssetVersion.
+func (s *Mapfix) GetAssetVersion() int64 {
+	return s.AssetVersion
+}
+
+// GetCompleted returns the value of Completed.
+func (s *Mapfix) GetCompleted() bool {
+	return s.Completed
+}
+
+// GetTargetAssetID returns the value of TargetAssetID.
+func (s *Mapfix) GetTargetAssetID() int64 {
+	return s.TargetAssetID
+}
+
+// GetStatusID returns the value of StatusID.
+func (s *Mapfix) GetStatusID() int32 {
+	return s.StatusID
+}
+
+// GetStatusMessage returns the value of StatusMessage.
+func (s *Mapfix) GetStatusMessage() string {
+	return s.StatusMessage
+}
+
+// SetID sets the value of ID.
+func (s *Mapfix) SetID(val int64) {
+	s.ID = val
+}
+
+// SetCreatedAt sets the value of CreatedAt.
+func (s *Mapfix) SetCreatedAt(val int64) {
+	s.CreatedAt = val
+}
+
+// SetUpdatedAt sets the value of UpdatedAt.
+func (s *Mapfix) SetUpdatedAt(val int64) {
+	s.UpdatedAt = val
+}
+
+// SetSubmitter sets the value of Submitter.
+func (s *Mapfix) SetSubmitter(val int64) {
+	s.Submitter = val
+}
+
+// SetAssetID sets the value of AssetID.
+func (s *Mapfix) SetAssetID(val int64) {
+	s.AssetID = val
+}
+
+// SetAssetVersion sets the value of AssetVersion.
+func (s *Mapfix) SetAssetVersion(val int64) {
+	s.AssetVersion = val
+}
+
+// SetCompleted sets the value of Completed.
+func (s *Mapfix) SetCompleted(val bool) {
+	s.Completed = val
+}
+
+// SetTargetAssetID sets the value of TargetAssetID.
+func (s *Mapfix) SetTargetAssetID(val int64) {
+	s.TargetAssetID = val
+}
+
+// SetStatusID sets the value of StatusID.
+func (s *Mapfix) SetStatusID(val int32) {
+	s.StatusID = val
+}
+
+// SetStatusMessage sets the value of StatusMessage.
+func (s *Mapfix) SetStatusMessage(val string) {
+	s.StatusMessage = val
+}
+
+// Ref: #/components/schemas/MapfixCreate
+type MapfixCreate struct {
+	AssetID       int64 `json:"AssetID"`
+	AssetVersion  int64 `json:"AssetVersion"`
+	TargetAssetID int64 `json:"TargetAssetID"`
+}
+
+// GetAssetID returns the value of AssetID.
+func (s *MapfixCreate) GetAssetID() int64 {
+	return s.AssetID
+}
+
+// GetAssetVersion returns the value of AssetVersion.
+func (s *MapfixCreate) GetAssetVersion() int64 {
+	return s.AssetVersion
+}
+
+// GetTargetAssetID returns the value of TargetAssetID.
+func (s *MapfixCreate) GetTargetAssetID() int64 {
+	return s.TargetAssetID
+}
+
+// SetAssetID sets the value of AssetID.
+func (s *MapfixCreate) SetAssetID(val int64) {
+	s.AssetID = val
+}
+
+// SetAssetVersion sets the value of AssetVersion.
+func (s *MapfixCreate) SetAssetVersion(val int64) {
+	s.AssetVersion = val
+}
+
+// SetTargetAssetID sets the value of TargetAssetID.
+func (s *MapfixCreate) SetTargetAssetID(val int64) {
+	s.TargetAssetID = val
+}
+
 // NewOptInt32 returns new OptInt32 with value set to v.
 func NewOptInt32(v int32) OptInt32 {
 	return OptInt32{
@@ -618,6 +796,9 @@ func (s *ScriptUpdate) SetResourceID(val OptInt64) {
 	s.ResourceID = val
 }
 
+// SetMapfixCompletedNoContent is response for SetMapfixCompleted operation.
+type SetMapfixCompletedNoContent struct{}
+
 // SetSubmissionCompletedNoContent is response for SetSubmissionCompleted operation.
 type SetSubmissionCompletedNoContent struct{}
 
@@ -849,6 +1030,9 @@ func (s *SubmissionCreate) SetAssetVersion(val int64) {
 	s.AssetVersion = val
 }
 
+// UpdateMapfixModelNoContent is response for UpdateMapfixModel operation.
+type UpdateMapfixModelNoContent struct{}
+
 // UpdateScriptNoContent is response for UpdateScript operation.
 type UpdateScriptNoContent struct{}
 
diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go
index 2d4a249..8b0b85c 100644
--- a/pkg/api/oas_server_gen.go
+++ b/pkg/api/oas_server_gen.go
@@ -8,6 +8,60 @@ import (
 
 // Handler handles operations described by OpenAPI v3 specification.
 type Handler interface {
+	// ActionMapfixAccepted implements actionMapfixAccepted operation.
+	//
+	// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
+	//
+	// POST /mapfixes/{MapfixID}/status/reset-validating
+	ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
+	// ActionMapfixReject implements actionMapfixReject operation.
+	//
+	// Role Reviewer changes status from Submitted -> Rejected.
+	//
+	// POST /mapfixes/{MapfixID}/status/reject
+	ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error
+	// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
+	//
+	// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+	//
+	// POST /mapfixes/{MapfixID}/status/request-changes
+	ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
+	// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
+	//
+	// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+	//
+	// POST /mapfixes/{MapfixID}/status/retry-validate
+	ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error
+	// ActionMapfixRevoke implements actionMapfixRevoke operation.
+	//
+	// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+	//
+	// POST /mapfixes/{MapfixID}/status/revoke
+	ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error
+	// ActionMapfixSubmit implements actionMapfixSubmit operation.
+	//
+	// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+	//
+	// POST /mapfixes/{MapfixID}/status/submit
+	ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error
+	// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
+	//
+	// Role Admin changes status from Validated -> Uploading.
+	//
+	// POST /mapfixes/{MapfixID}/status/trigger-upload
+	ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error
+	// ActionMapfixTriggerValidate implements actionMapfixTriggerValidate operation.
+	//
+	// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+	//
+	// POST /mapfixes/{MapfixID}/status/trigger-validate
+	ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error
+	// ActionMapfixValidated implements actionMapfixValidated operation.
+	//
+	// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
+	//
+	// POST /mapfixes/{MapfixID}/status/reset-uploading
+	ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
 	// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
 	//
 	// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
@@ -62,6 +116,12 @@ type Handler interface {
 	//
 	// POST /submissions/{SubmissionID}/status/reset-uploading
 	ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error
+	// CreateMapfix implements createMapfix operation.
+	//
+	// Create new mapfix.
+	//
+	// POST /mapfixes
+	CreateMapfix(ctx context.Context, req *MapfixCreate) (*ID, error)
 	// CreateScript implements createScript operation.
 	//
 	// Create a new script.
@@ -92,6 +152,12 @@ type Handler interface {
 	//
 	// DELETE /script-policy/{ScriptPolicyID}
 	DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error
+	// GetMapfix implements getMapfix operation.
+	//
+	// Retrieve map with ID.
+	//
+	// GET /mapfixes/{MapfixID}
+	GetMapfix(ctx context.Context, params GetMapfixParams) (*Mapfix, error)
 	// GetScript implements getScript operation.
 	//
 	// Get the specified script by ID.
@@ -110,6 +176,12 @@ type Handler interface {
 	//
 	// GET /submissions/{SubmissionID}
 	GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
+	// ListMapfixes implements listMapfixes operation.
+	//
+	// Get list of mapfixes.
+	//
+	// GET /mapfixes
+	ListMapfixes(ctx context.Context, params ListMapfixesParams) ([]Mapfix, error)
 	// ListScriptPolicy implements listScriptPolicy operation.
 	//
 	// Get list of script policies.
@@ -152,12 +224,24 @@ type Handler interface {
 	//
 	// GET /session/validate
 	SessionValidate(ctx context.Context) (bool, error)
+	// SetMapfixCompleted implements setMapfixCompleted operation.
+	//
+	// Called by maptest when a player completes the map.
+	//
+	// POST /mapfixes/{MapfixID}/completed
+	SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error
 	// SetSubmissionCompleted implements setSubmissionCompleted operation.
 	//
 	// Called by maptest when a player completes the map.
 	//
 	// POST /submissions/{SubmissionID}/completed
 	SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error
+	// UpdateMapfixModel implements updateMapfixModel operation.
+	//
+	// Update model following role restrictions.
+	//
+	// POST /mapfixes/{MapfixID}/model
+	UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error
 	// UpdateScript implements updateScript operation.
 	//
 	// Update the specified script by ID.
diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go
index a74716b..78953e1 100644
--- a/pkg/api/oas_unimplemented_gen.go
+++ b/pkg/api/oas_unimplemented_gen.go
@@ -13,6 +13,87 @@ type UnimplementedHandler struct{}
 
 var _ Handler = UnimplementedHandler{}
 
+// ActionMapfixAccepted implements actionMapfixAccepted operation.
+//
+// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/reset-validating
+func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixReject implements actionMapfixReject operation.
+//
+// Role Reviewer changes status from Submitted -> Rejected.
+//
+// POST /mapfixes/{MapfixID}/status/reject
+func (UnimplementedHandler) ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
+//
+// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+//
+// POST /mapfixes/{MapfixID}/status/request-changes
+func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
+//
+// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/retry-validate
+func (UnimplementedHandler) ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixRevoke implements actionMapfixRevoke operation.
+//
+// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+//
+// POST /mapfixes/{MapfixID}/status/revoke
+func (UnimplementedHandler) ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixSubmit implements actionMapfixSubmit operation.
+//
+// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+//
+// POST /mapfixes/{MapfixID}/status/submit
+func (UnimplementedHandler) ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
+//
+// Role Admin changes status from Validated -> Uploading.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-upload
+func (UnimplementedHandler) ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixTriggerValidate implements actionMapfixTriggerValidate operation.
+//
+// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-validate
+func (UnimplementedHandler) ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixValidated implements actionMapfixValidated operation.
+//
+// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/reset-uploading
+func (UnimplementedHandler) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
+	return ht.ErrNotImplemented
+}
+
 // ActionSubmissionAccepted implements actionSubmissionAccepted operation.
 //
 // Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
@@ -94,6 +175,15 @@ func (UnimplementedHandler) ActionSubmissionValidated(ctx context.Context, param
 	return ht.ErrNotImplemented
 }
 
+// CreateMapfix implements createMapfix operation.
+//
+// Create new mapfix.
+//
+// POST /mapfixes
+func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixCreate) (r *ID, _ error) {
+	return r, ht.ErrNotImplemented
+}
+
 // CreateScript implements createScript operation.
 //
 // Create a new script.
@@ -139,6 +229,15 @@ func (UnimplementedHandler) DeleteScriptPolicy(ctx context.Context, params Delet
 	return ht.ErrNotImplemented
 }
 
+// GetMapfix implements getMapfix operation.
+//
+// Retrieve map with ID.
+//
+// GET /mapfixes/{MapfixID}
+func (UnimplementedHandler) GetMapfix(ctx context.Context, params GetMapfixParams) (r *Mapfix, _ error) {
+	return r, ht.ErrNotImplemented
+}
+
 // GetScript implements getScript operation.
 //
 // Get the specified script by ID.
@@ -166,6 +265,15 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss
 	return r, ht.ErrNotImplemented
 }
 
+// ListMapfixes implements listMapfixes operation.
+//
+// Get list of mapfixes.
+//
+// GET /mapfixes
+func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r []Mapfix, _ error) {
+	return r, ht.ErrNotImplemented
+}
+
 // ListScriptPolicy implements listScriptPolicy operation.
 //
 // Get list of script policies.
@@ -229,6 +337,15 @@ func (UnimplementedHandler) SessionValidate(ctx context.Context) (r bool, _ erro
 	return r, ht.ErrNotImplemented
 }
 
+// SetMapfixCompleted implements setMapfixCompleted operation.
+//
+// Called by maptest when a player completes the map.
+//
+// POST /mapfixes/{MapfixID}/completed
+func (UnimplementedHandler) SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error {
+	return ht.ErrNotImplemented
+}
+
 // SetSubmissionCompleted implements setSubmissionCompleted operation.
 //
 // Called by maptest when a player completes the map.
@@ -238,6 +355,15 @@ func (UnimplementedHandler) SetSubmissionCompleted(ctx context.Context, params S
 	return ht.ErrNotImplemented
 }
 
+// UpdateMapfixModel implements updateMapfixModel operation.
+//
+// Update model following role restrictions.
+//
+// POST /mapfixes/{MapfixID}/model
+func (UnimplementedHandler) UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error {
+	return ht.ErrNotImplemented
+}
+
 // UpdateScript implements updateScript operation.
 //
 // Update the specified script by ID.
diff --git a/pkg/api/oas_validators_gen.go b/pkg/api/oas_validators_gen.go
index 3b095dc..098ea69 100644
--- a/pkg/api/oas_validators_gen.go
+++ b/pkg/api/oas_validators_gen.go
@@ -8,6 +8,37 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+func (s *Mapfix) Validate() error {
+	if s == nil {
+		return validate.ErrNilPointer
+	}
+
+	var failures []validate.FieldError
+	if err := func() error {
+		if err := (validate.String{
+			MinLength:    0,
+			MinLengthSet: false,
+			MaxLength:    256,
+			MaxLengthSet: true,
+			Email:        false,
+			Hostname:     false,
+			Regex:        nil,
+		}).Validate(string(s.StatusMessage)); err != nil {
+			return errors.Wrap(err, "string")
+		}
+		return nil
+	}(); err != nil {
+		failures = append(failures, validate.FieldError{
+			Name:  "StatusMessage",
+			Error: err,
+		})
+	}
+	if len(failures) > 0 {
+		return &validate.Error{Fields: failures}
+	}
+	return nil
+}
+
 func (s *Script) Validate() error {
 	if s == nil {
 		return validate.ErrNilPointer
diff --git a/pkg/internal/oas_client_gen.go b/pkg/internal/oas_client_gen.go
index 91bfd06..8c64dc5 100644
--- a/pkg/internal/oas_client_gen.go
+++ b/pkg/internal/oas_client_gen.go
@@ -28,6 +28,24 @@ func trimTrailingSlashes(u *url.URL) {
 
 // Invoker invokes operations described by OpenAPI v3 specification.
 type Invoker interface {
+	// ActionMapfixAccepted invokes actionMapfixAccepted operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-failed
+	ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
+	// ActionMapfixUploaded invokes actionMapfixUploaded operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-uploaded
+	ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error
+	// ActionMapfixValidated invokes actionMapfixValidated operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Validating -> Validated.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-validated
+	ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
 	// ActionSubmissionAccepted invokes actionSubmissionAccepted operation.
 	//
 	// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
@@ -76,6 +94,12 @@ type Invoker interface {
 	//
 	// GET /scripts
 	ListScripts(ctx context.Context, params ListScriptsParams) ([]Script, error)
+	// UpdateMapfixValidatedModel invokes updateMapfixValidatedModel operation.
+	//
+	// Update validated model.
+	//
+	// POST /mapfixes/{MapfixID}/validated-model
+	UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error
 	// UpdateSubmissionValidatedModel invokes updateSubmissionValidatedModel operation.
 	//
 	// Update validated model.
@@ -131,6 +155,297 @@ func (c *Client) requestURL(ctx context.Context) *url.URL {
 	return u
 }
 
+// ActionMapfixAccepted invokes actionMapfixAccepted operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/validator-failed
+func (c *Client) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
+	_, err := c.sendActionMapfixAccepted(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) (res *ActionMapfixAcceptedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixAccepted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-failed"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixAcceptedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/validator-failed"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeQueryParams"
+	q := uri.NewQueryEncoder()
+	{
+		// Encode "StatusMessage" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "StatusMessage",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.StringToString(params.StatusMessage))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	u.RawQuery = q.Values().Encode()
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixAcceptedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixUploaded invokes actionMapfixUploaded operation.
+//
+// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+//
+// POST /mapfixes/{MapfixID}/status/validator-uploaded
+func (c *Client) ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error {
+	_, err := c.sendActionMapfixUploaded(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) (res *ActionMapfixUploadedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixUploaded"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-uploaded"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixUploadedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/validator-uploaded"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixUploadedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
+// ActionMapfixValidated invokes actionMapfixValidated operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/validator-validated
+func (c *Client) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
+	_, err := c.sendActionMapfixValidated(ctx, params)
+	return err
+}
+
+func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) (res *ActionMapfixValidatedNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixValidated"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-validated"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixValidatedOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/status/validator-validated"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeActionMapfixValidatedResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // ActionSubmissionAccepted invokes actionSubmissionAccepted operation.
 //
 // (Internal endpoint) Role Validator changes status from Validating -> Accepted.
@@ -1024,6 +1339,129 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams)
 	return result, nil
 }
 
+// UpdateMapfixValidatedModel invokes updateMapfixValidatedModel operation.
+//
+// Update validated model.
+//
+// POST /mapfixes/{MapfixID}/validated-model
+func (c *Client) UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error {
+	_, err := c.sendUpdateMapfixValidatedModel(ctx, params)
+	return err
+}
+
+func (c *Client) sendUpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) (res *UpdateMapfixValidatedModelNoContent, err error) {
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("updateMapfixValidatedModel"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/validated-model"),
+	}
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		elapsedDuration := time.Since(startTime)
+		c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+	}()
+
+	// Increment request counter.
+	c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+	// Start a span for this request.
+	ctx, span := c.cfg.Tracer.Start(ctx, UpdateMapfixValidatedModelOperation,
+		trace.WithAttributes(otelAttrs...),
+		clientSpanKind,
+	)
+	// Track stage for error reporting.
+	var stage string
+	defer func() {
+		if err != nil {
+			span.RecordError(err)
+			span.SetStatus(codes.Error, stage)
+			c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+		}
+		span.End()
+	}()
+
+	stage = "BuildURL"
+	u := uri.Clone(c.requestURL(ctx))
+	var pathParts [3]string
+	pathParts[0] = "/mapfixes/"
+	{
+		// Encode "MapfixID" parameter.
+		e := uri.NewPathEncoder(uri.PathEncoderConfig{
+			Param:   "MapfixID",
+			Style:   uri.PathStyleSimple,
+			Explode: false,
+		})
+		if err := func() error {
+			return e.EncodeValue(conv.Int64ToString(params.MapfixID))
+		}(); err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		encoded, err := e.Result()
+		if err != nil {
+			return res, errors.Wrap(err, "encode path")
+		}
+		pathParts[1] = encoded
+	}
+	pathParts[2] = "/validated-model"
+	uri.AddPathParts(u, pathParts[:]...)
+
+	stage = "EncodeQueryParams"
+	q := uri.NewQueryEncoder()
+	{
+		// Encode "ValidatedModelID" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "ValidatedModelID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int64ToString(params.ValidatedModelID))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	{
+		// Encode "ValidatedModelVersion" parameter.
+		cfg := uri.QueryParameterEncodingConfig{
+			Name:    "ValidatedModelVersion",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+			return e.EncodeValue(conv.Int64ToString(params.ValidatedModelVersion))
+		}); err != nil {
+			return res, errors.Wrap(err, "encode query")
+		}
+	}
+	u.RawQuery = q.Values().Encode()
+
+	stage = "EncodeRequest"
+	r, err := ht.NewRequest(ctx, "POST", u)
+	if err != nil {
+		return res, errors.Wrap(err, "create request")
+	}
+
+	stage = "SendRequest"
+	resp, err := c.cfg.Client.Do(r)
+	if err != nil {
+		return res, errors.Wrap(err, "do request")
+	}
+	defer resp.Body.Close()
+
+	stage = "DecodeResponse"
+	result, err := decodeUpdateMapfixValidatedModelResponse(resp)
+	if err != nil {
+		return res, errors.Wrap(err, "decode response")
+	}
+
+	return result, nil
+}
+
 // UpdateSubmissionValidatedModel invokes updateSubmissionValidatedModel operation.
 //
 // Update validated model.
diff --git a/pkg/internal/oas_handlers_gen.go b/pkg/internal/oas_handlers_gen.go
index b8bc5c3..346fefb 100644
--- a/pkg/internal/oas_handlers_gen.go
+++ b/pkg/internal/oas_handlers_gen.go
@@ -30,6 +30,457 @@ func (c *codeRecorder) WriteHeader(status int) {
 	c.ResponseWriter.WriteHeader(status)
 }
 
+// handleActionMapfixAcceptedRequest handles actionMapfixAccepted operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/validator-failed
+func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixAccepted"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-failed"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixAcceptedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixAcceptedOperation,
+			ID:   "actionMapfixAccepted",
+		}
+	)
+	params, err := decodeActionMapfixAcceptedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixAcceptedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixAcceptedOperation,
+			OperationSummary: "(Internal endpoint) Role Validator changes status from Validating -> Accepted",
+			OperationID:      "actionMapfixAccepted",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+				{
+					Name: "StatusMessage",
+					In:   "query",
+				}: params.StatusMessage,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixAcceptedParams
+			Response = *ActionMapfixAcceptedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixAcceptedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixAccepted(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixAccepted(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixAcceptedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixUploadedRequest handles actionMapfixUploaded operation.
+//
+// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+//
+// POST /mapfixes/{MapfixID}/status/validator-uploaded
+func (s *Server) handleActionMapfixUploadedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixUploaded"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-uploaded"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixUploadedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixUploadedOperation,
+			ID:   "actionMapfixUploaded",
+		}
+	)
+	params, err := decodeActionMapfixUploadedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixUploadedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixUploadedOperation,
+			OperationSummary: "(Internal endpoint) Role Validator changes status from Uploading -> Uploaded",
+			OperationID:      "actionMapfixUploaded",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixUploadedParams
+			Response = *ActionMapfixUploadedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixUploadedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixUploaded(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixUploaded(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixUploadedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
+// handleActionMapfixValidatedRequest handles actionMapfixValidated operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/validator-validated
+func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("actionMapfixValidated"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-validated"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixValidatedOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: ActionMapfixValidatedOperation,
+			ID:   "actionMapfixValidated",
+		}
+	)
+	params, err := decodeActionMapfixValidatedParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *ActionMapfixValidatedNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    ActionMapfixValidatedOperation,
+			OperationSummary: "(Internal endpoint) Role Validator changes status from Validating -> Validated",
+			OperationID:      "actionMapfixValidated",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = ActionMapfixValidatedParams
+			Response = *ActionMapfixValidatedNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackActionMapfixValidatedParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.ActionMapfixValidated(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.ActionMapfixValidated(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeActionMapfixValidatedResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleActionSubmissionAcceptedRequest handles actionSubmissionAccepted operation.
 //
 // (Internal endpoint) Role Validator changes status from Validating -> Accepted.
@@ -1270,6 +1721,163 @@ func (s *Server) handleListScriptsRequest(args [0]string, argsEscaped bool, w ht
 	}
 }
 
+// handleUpdateMapfixValidatedModelRequest handles updateMapfixValidatedModel operation.
+//
+// Update validated model.
+//
+// POST /mapfixes/{MapfixID}/validated-model
+func (s *Server) handleUpdateMapfixValidatedModelRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+	statusWriter := &codeRecorder{ResponseWriter: w}
+	w = statusWriter
+	otelAttrs := []attribute.KeyValue{
+		otelogen.OperationID("updateMapfixValidatedModel"),
+		semconv.HTTPRequestMethodKey.String("POST"),
+		semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/validated-model"),
+	}
+
+	// Start a span for this request.
+	ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateMapfixValidatedModelOperation,
+		trace.WithAttributes(otelAttrs...),
+		serverSpanKind,
+	)
+	defer span.End()
+
+	// Add Labeler to context.
+	labeler := &Labeler{attrs: otelAttrs}
+	ctx = contextWithLabeler(ctx, labeler)
+
+	// Run stopwatch.
+	startTime := time.Now()
+	defer func() {
+		elapsedDuration := time.Since(startTime)
+
+		attrSet := labeler.AttributeSet()
+		attrs := attrSet.ToSlice()
+		code := statusWriter.status
+		if code != 0 {
+			codeAttr := semconv.HTTPResponseStatusCode(code)
+			attrs = append(attrs, codeAttr)
+			span.SetAttributes(codeAttr)
+		}
+		attrOpt := metric.WithAttributes(attrs...)
+
+		// Increment request counter.
+		s.requests.Add(ctx, 1, attrOpt)
+
+		// Use floating point division here for higher precision (instead of Millisecond method).
+		s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+	}()
+
+	var (
+		recordError = func(stage string, err error) {
+			span.RecordError(err)
+
+			// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+			// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+			// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+			// max redirects exceeded), in which case status MUST be set to Error.
+			code := statusWriter.status
+			if code >= 100 && code < 500 {
+				span.SetStatus(codes.Error, stage)
+			}
+
+			attrSet := labeler.AttributeSet()
+			attrs := attrSet.ToSlice()
+			if code != 0 {
+				attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+			}
+
+			s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+		}
+		err          error
+		opErrContext = ogenerrors.OperationContext{
+			Name: UpdateMapfixValidatedModelOperation,
+			ID:   "updateMapfixValidatedModel",
+		}
+	)
+	params, err := decodeUpdateMapfixValidatedModelParams(args, argsEscaped, r)
+	if err != nil {
+		err = &ogenerrors.DecodeParamsError{
+			OperationContext: opErrContext,
+			Err:              err,
+		}
+		defer recordError("DecodeParams", err)
+		s.cfg.ErrorHandler(ctx, w, r, err)
+		return
+	}
+
+	var response *UpdateMapfixValidatedModelNoContent
+	if m := s.cfg.Middleware; m != nil {
+		mreq := middleware.Request{
+			Context:          ctx,
+			OperationName:    UpdateMapfixValidatedModelOperation,
+			OperationSummary: "Update validated model",
+			OperationID:      "updateMapfixValidatedModel",
+			Body:             nil,
+			Params: middleware.Parameters{
+				{
+					Name: "MapfixID",
+					In:   "path",
+				}: params.MapfixID,
+				{
+					Name: "ValidatedModelID",
+					In:   "query",
+				}: params.ValidatedModelID,
+				{
+					Name: "ValidatedModelVersion",
+					In:   "query",
+				}: params.ValidatedModelVersion,
+			},
+			Raw: r,
+		}
+
+		type (
+			Request  = struct{}
+			Params   = UpdateMapfixValidatedModelParams
+			Response = *UpdateMapfixValidatedModelNoContent
+		)
+		response, err = middleware.HookMiddleware[
+			Request,
+			Params,
+			Response,
+		](
+			m,
+			mreq,
+			unpackUpdateMapfixValidatedModelParams,
+			func(ctx context.Context, request Request, params Params) (response Response, err error) {
+				err = s.h.UpdateMapfixValidatedModel(ctx, params)
+				return response, err
+			},
+		)
+	} else {
+		err = s.h.UpdateMapfixValidatedModel(ctx, params)
+	}
+	if err != nil {
+		if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
+			if err := encodeErrorResponse(errRes, w, span); err != nil {
+				defer recordError("Internal", err)
+			}
+			return
+		}
+		if errors.Is(err, ht.ErrNotImplemented) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+			return
+		}
+		if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
+			defer recordError("Internal", err)
+		}
+		return
+	}
+
+	if err := encodeUpdateMapfixValidatedModelResponse(response, w, span); err != nil {
+		defer recordError("EncodeResponse", err)
+		if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+			s.cfg.ErrorHandler(ctx, w, r, err)
+		}
+		return
+	}
+}
+
 // handleUpdateSubmissionValidatedModelRequest handles updateSubmissionValidatedModel operation.
 //
 // Update validated model.
diff --git a/pkg/internal/oas_operations_gen.go b/pkg/internal/oas_operations_gen.go
index 7e45640..d472077 100644
--- a/pkg/internal/oas_operations_gen.go
+++ b/pkg/internal/oas_operations_gen.go
@@ -6,6 +6,9 @@ package api
 type OperationName = string
 
 const (
+	ActionMapfixAcceptedOperation           OperationName = "ActionMapfixAccepted"
+	ActionMapfixUploadedOperation           OperationName = "ActionMapfixUploaded"
+	ActionMapfixValidatedOperation          OperationName = "ActionMapfixValidated"
 	ActionSubmissionAcceptedOperation       OperationName = "ActionSubmissionAccepted"
 	ActionSubmissionUploadedOperation       OperationName = "ActionSubmissionUploaded"
 	ActionSubmissionValidatedOperation      OperationName = "ActionSubmissionValidated"
@@ -14,5 +17,6 @@ const (
 	GetScriptOperation                      OperationName = "GetScript"
 	ListScriptPolicyOperation               OperationName = "ListScriptPolicy"
 	ListScriptsOperation                    OperationName = "ListScripts"
+	UpdateMapfixValidatedModelOperation     OperationName = "UpdateMapfixValidatedModel"
 	UpdateSubmissionValidatedModelOperation OperationName = "UpdateSubmissionValidatedModel"
 )
diff --git a/pkg/internal/oas_parameters_gen.go b/pkg/internal/oas_parameters_gen.go
index 0744fce..5ce0a6b 100644
--- a/pkg/internal/oas_parameters_gen.go
+++ b/pkg/internal/oas_parameters_gen.go
@@ -15,6 +15,265 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+// ActionMapfixAcceptedParams is parameters of actionMapfixAccepted operation.
+type ActionMapfixAcceptedParams struct {
+	// The unique identifier for a submission.
+	MapfixID      int64
+	StatusMessage string
+}
+
+func unpackActionMapfixAcceptedParams(packed middleware.Parameters) (params ActionMapfixAcceptedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "StatusMessage",
+			In:   "query",
+		}
+		params.StatusMessage = packed[key].(string)
+	}
+	return params
+}
+
+func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixAcceptedParams, _ error) {
+	q := uri.NewQueryDecoder(r.URL.Query())
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	// Decode query: StatusMessage.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "StatusMessage",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToString(val)
+				if err != nil {
+					return err
+				}
+
+				params.StatusMessage = c
+				return nil
+			}); err != nil {
+				return err
+			}
+			if err := func() error {
+				if err := (validate.String{
+					MinLength:    0,
+					MinLengthSet: true,
+					MaxLength:    4096,
+					MaxLengthSet: true,
+					Email:        false,
+					Hostname:     false,
+					Regex:        nil,
+				}).Validate(string(params.StatusMessage)); err != nil {
+					return errors.Wrap(err, "string")
+				}
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "StatusMessage",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixUploadedParams is parameters of actionMapfixUploaded operation.
+type ActionMapfixUploadedParams struct {
+	// The unique identifier for a submission.
+	MapfixID int64
+}
+
+func unpackActionMapfixUploadedParams(packed middleware.Parameters) (params ActionMapfixUploadedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixUploadedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixUploadedParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
+// ActionMapfixValidatedParams is parameters of actionMapfixValidated operation.
+type ActionMapfixValidatedParams struct {
+	// The unique identifier for a submission.
+	MapfixID int64
+}
+
+func unpackActionMapfixValidatedParams(packed middleware.Parameters) (params ActionMapfixValidatedParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeActionMapfixValidatedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixValidatedParams, _ error) {
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // ActionSubmissionAcceptedParams is parameters of actionSubmissionAccepted operation.
 type ActionSubmissionAcceptedParams struct {
 	// The unique identifier for a submission.
@@ -1155,6 +1414,161 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request)
 	return params, nil
 }
 
+// UpdateMapfixValidatedModelParams is parameters of updateMapfixValidatedModel operation.
+type UpdateMapfixValidatedModelParams struct {
+	// The unique identifier for a submission.
+	MapfixID              int64
+	ValidatedModelID      int64
+	ValidatedModelVersion int64
+}
+
+func unpackUpdateMapfixValidatedModelParams(packed middleware.Parameters) (params UpdateMapfixValidatedModelParams) {
+	{
+		key := middleware.ParameterKey{
+			Name: "MapfixID",
+			In:   "path",
+		}
+		params.MapfixID = packed[key].(int64)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "ValidatedModelID",
+			In:   "query",
+		}
+		params.ValidatedModelID = packed[key].(int64)
+	}
+	{
+		key := middleware.ParameterKey{
+			Name: "ValidatedModelVersion",
+			In:   "query",
+		}
+		params.ValidatedModelVersion = packed[key].(int64)
+	}
+	return params
+}
+
+func decodeUpdateMapfixValidatedModelParams(args [1]string, argsEscaped bool, r *http.Request) (params UpdateMapfixValidatedModelParams, _ error) {
+	q := uri.NewQueryDecoder(r.URL.Query())
+	// Decode path: MapfixID.
+	if err := func() error {
+		param := args[0]
+		if argsEscaped {
+			unescaped, err := url.PathUnescape(args[0])
+			if err != nil {
+				return errors.Wrap(err, "unescape path")
+			}
+			param = unescaped
+		}
+		if len(param) > 0 {
+			d := uri.NewPathDecoder(uri.PathDecoderConfig{
+				Param:   "MapfixID",
+				Value:   param,
+				Style:   uri.PathStyleSimple,
+				Explode: false,
+			})
+
+			if err := func() error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.MapfixID = c
+				return nil
+			}(); err != nil {
+				return err
+			}
+		} else {
+			return validate.ErrFieldRequired
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "MapfixID",
+			In:   "path",
+			Err:  err,
+		}
+	}
+	// Decode query: ValidatedModelID.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "ValidatedModelID",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.ValidatedModelID = c
+				return nil
+			}); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "ValidatedModelID",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	// Decode query: ValidatedModelVersion.
+	if err := func() error {
+		cfg := uri.QueryParameterDecodingConfig{
+			Name:    "ValidatedModelVersion",
+			Style:   uri.QueryStyleForm,
+			Explode: true,
+		}
+
+		if err := q.HasParam(cfg); err == nil {
+			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+				val, err := d.DecodeValue()
+				if err != nil {
+					return err
+				}
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.ValidatedModelVersion = c
+				return nil
+			}); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
+	}(); err != nil {
+		return params, &ogenerrors.DecodeParamError{
+			Name: "ValidatedModelVersion",
+			In:   "query",
+			Err:  err,
+		}
+	}
+	return params, nil
+}
+
 // UpdateSubmissionValidatedModelParams is parameters of updateSubmissionValidatedModel operation.
 type UpdateSubmissionValidatedModelParams struct {
 	// The unique identifier for a submission.
diff --git a/pkg/internal/oas_response_decoders_gen.go b/pkg/internal/oas_response_decoders_gen.go
index 12ac6e4..226883f 100644
--- a/pkg/internal/oas_response_decoders_gen.go
+++ b/pkg/internal/oas_response_decoders_gen.go
@@ -15,6 +15,159 @@ import (
 	"github.com/ogen-go/ogen/validate"
 )
 
+func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixAcceptedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixAcceptedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixUploadedResponse(resp *http.Response) (res *ActionMapfixUploadedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixUploadedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
+func decodeActionMapfixValidatedResponse(resp *http.Response) (res *ActionMapfixValidatedNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &ActionMapfixValidatedNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSubmissionAcceptedNoContent, _ error) {
 	switch resp.StatusCode {
 	case 204:
@@ -660,6 +813,57 @@ func decodeListScriptsResponse(resp *http.Response) (res []Script, _ error) {
 	return res, errors.Wrap(defRes, "error")
 }
 
+func decodeUpdateMapfixValidatedModelResponse(resp *http.Response) (res *UpdateMapfixValidatedModelNoContent, _ error) {
+	switch resp.StatusCode {
+	case 204:
+		// Code 204.
+		return &UpdateMapfixValidatedModelNoContent{}, nil
+	}
+	// Convenient error response.
+	defRes, err := func() (res *ErrorStatusCode, err error) {
+		ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+		if err != nil {
+			return res, errors.Wrap(err, "parse media type")
+		}
+		switch {
+		case ct == "application/json":
+			buf, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return res, err
+			}
+			d := jx.DecodeBytes(buf)
+
+			var response Error
+			if err := func() error {
+				if err := response.Decode(d); err != nil {
+					return err
+				}
+				if err := d.Skip(); err != io.EOF {
+					return errors.New("unexpected trailing data")
+				}
+				return nil
+			}(); err != nil {
+				err = &ogenerrors.DecodeBodyError{
+					ContentType: ct,
+					Body:        buf,
+					Err:         err,
+				}
+				return res, err
+			}
+			return &ErrorStatusCode{
+				StatusCode: resp.StatusCode,
+				Response:   response,
+			}, nil
+		default:
+			return res, validate.InvalidContentType(ct)
+		}
+	}()
+	if err != nil {
+		return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
+	}
+	return res, errors.Wrap(defRes, "error")
+}
+
 func decodeUpdateSubmissionValidatedModelResponse(resp *http.Response) (res *UpdateSubmissionValidatedModelNoContent, _ error) {
 	switch resp.StatusCode {
 	case 204:
diff --git a/pkg/internal/oas_response_encoders_gen.go b/pkg/internal/oas_response_encoders_gen.go
index 4ded4b7..c7d2b1f 100644
--- a/pkg/internal/oas_response_encoders_gen.go
+++ b/pkg/internal/oas_response_encoders_gen.go
@@ -13,6 +13,27 @@ import (
 	ht "github.com/ogen-go/ogen/http"
 )
 
+func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixUploadedResponse(response *ActionMapfixUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
+func encodeActionMapfixValidatedResponse(response *ActionMapfixValidatedNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
 func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
 	w.WriteHeader(204)
 	span.SetStatus(codes.Ok, http.StatusText(204))
@@ -112,6 +133,13 @@ func encodeListScriptsResponse(response []Script, w http.ResponseWriter, span tr
 	return nil
 }
 
+func encodeUpdateMapfixValidatedModelResponse(response *UpdateMapfixValidatedModelNoContent, w http.ResponseWriter, span trace.Span) error {
+	w.WriteHeader(204)
+	span.SetStatus(codes.Ok, http.StatusText(204))
+
+	return nil
+}
+
 func encodeUpdateSubmissionValidatedModelResponse(response *UpdateSubmissionValidatedModelNoContent, w http.ResponseWriter, span trace.Span) error {
 	w.WriteHeader(204)
 	span.SetStatus(codes.Ok, http.StatusText(204))
diff --git a/pkg/internal/oas_router_gen.go b/pkg/internal/oas_router_gen.go
index 6079083..77e8063 100644
--- a/pkg/internal/oas_router_gen.go
+++ b/pkg/internal/oas_router_gen.go
@@ -49,9 +49,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			break
 		}
 		switch elem[0] {
-		case '/': // Prefix: "/s"
+		case '/': // Prefix: "/"
 
-			if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" {
+			if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
 				elem = elem[l:]
 			} else {
 				break
@@ -61,105 +61,15 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 				break
 			}
 			switch elem[0] {
-			case 'c': // Prefix: "cript"
+			case 'm': // Prefix: "mapfixes/"
 
-				if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
+				if l := len("mapfixes/"); len(elem) >= l && elem[0:l] == "mapfixes/" {
 					elem = elem[l:]
 				} else {
 					break
 				}
 
-				if len(elem) == 0 {
-					break
-				}
-				switch elem[0] {
-				case '-': // Prefix: "-policy"
-
-					if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
-						elem = elem[l:]
-					} else {
-						break
-					}
-
-					if len(elem) == 0 {
-						// Leaf node.
-						switch r.Method {
-						case "GET":
-							s.handleListScriptPolicyRequest([0]string{}, elemIsEscaped, w, r)
-						case "POST":
-							s.handleCreateScriptPolicyRequest([0]string{}, elemIsEscaped, w, r)
-						default:
-							s.notAllowed(w, r, "GET,POST")
-						}
-
-						return
-					}
-
-				case 's': // Prefix: "s"
-
-					if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
-						elem = elem[l:]
-					} else {
-						break
-					}
-
-					if len(elem) == 0 {
-						switch r.Method {
-						case "GET":
-							s.handleListScriptsRequest([0]string{}, elemIsEscaped, w, r)
-						case "POST":
-							s.handleCreateScriptRequest([0]string{}, elemIsEscaped, w, r)
-						default:
-							s.notAllowed(w, r, "GET,POST")
-						}
-
-						return
-					}
-					switch elem[0] {
-					case '/': // Prefix: "/"
-
-						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
-							elem = elem[l:]
-						} else {
-							break
-						}
-
-						// Param: "ScriptID"
-						// Leaf parameter, slashes are prohibited
-						idx := strings.IndexByte(elem, '/')
-						if idx >= 0 {
-							break
-						}
-						args[0] = elem
-						elem = ""
-
-						if len(elem) == 0 {
-							// Leaf node.
-							switch r.Method {
-							case "GET":
-								s.handleGetScriptRequest([1]string{
-									args[0],
-								}, elemIsEscaped, w, r)
-							default:
-								s.notAllowed(w, r, "GET")
-							}
-
-							return
-						}
-
-					}
-
-				}
-
-			case 'u': // Prefix: "ubmissions/"
-
-				if l := len("ubmissions/"); len(elem) >= l && elem[0:l] == "ubmissions/" {
-					elem = elem[l:]
-				} else {
-					break
-				}
-
-				// Param: "SubmissionID"
+				// Param: "MapfixID"
 				// Match until "/"
 				idx := strings.IndexByte(elem, '/')
 				if idx < 0 {
@@ -208,7 +118,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 								// Leaf node.
 								switch r.Method {
 								case "POST":
-									s.handleActionSubmissionAcceptedRequest([1]string{
+									s.handleActionMapfixAcceptedRequest([1]string{
 										args[0],
 									}, elemIsEscaped, w, r)
 								default:
@@ -230,7 +140,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 								// Leaf node.
 								switch r.Method {
 								case "POST":
-									s.handleActionSubmissionUploadedRequest([1]string{
+									s.handleActionMapfixUploadedRequest([1]string{
 										args[0],
 									}, elemIsEscaped, w, r)
 								default:
@@ -252,7 +162,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 								// Leaf node.
 								switch r.Method {
 								case "POST":
-									s.handleActionSubmissionValidatedRequest([1]string{
+									s.handleActionMapfixValidatedRequest([1]string{
 										args[0],
 									}, elemIsEscaped, w, r)
 								default:
@@ -276,7 +186,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 							// Leaf node.
 							switch r.Method {
 							case "POST":
-								s.handleUpdateSubmissionValidatedModelRequest([1]string{
+								s.handleUpdateMapfixValidatedModelRequest([1]string{
 									args[0],
 								}, elemIsEscaped, w, r)
 							default:
@@ -290,6 +200,249 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 				}
 
+			case 's': // Prefix: "s"
+
+				if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
+					elem = elem[l:]
+				} else {
+					break
+				}
+
+				if len(elem) == 0 {
+					break
+				}
+				switch elem[0] {
+				case 'c': // Prefix: "cript"
+
+					if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					if len(elem) == 0 {
+						break
+					}
+					switch elem[0] {
+					case '-': // Prefix: "-policy"
+
+						if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							// Leaf node.
+							switch r.Method {
+							case "GET":
+								s.handleListScriptPolicyRequest([0]string{}, elemIsEscaped, w, r)
+							case "POST":
+								s.handleCreateScriptPolicyRequest([0]string{}, elemIsEscaped, w, r)
+							default:
+								s.notAllowed(w, r, "GET,POST")
+							}
+
+							return
+						}
+
+					case 's': // Prefix: "s"
+
+						if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							switch r.Method {
+							case "GET":
+								s.handleListScriptsRequest([0]string{}, elemIsEscaped, w, r)
+							case "POST":
+								s.handleCreateScriptRequest([0]string{}, elemIsEscaped, w, r)
+							default:
+								s.notAllowed(w, r, "GET,POST")
+							}
+
+							return
+						}
+						switch elem[0] {
+						case '/': // Prefix: "/"
+
+							if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							// Param: "ScriptID"
+							// Leaf parameter, slashes are prohibited
+							idx := strings.IndexByte(elem, '/')
+							if idx >= 0 {
+								break
+							}
+							args[0] = elem
+							elem = ""
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch r.Method {
+								case "GET":
+									s.handleGetScriptRequest([1]string{
+										args[0],
+									}, elemIsEscaped, w, r)
+								default:
+									s.notAllowed(w, r, "GET")
+								}
+
+								return
+							}
+
+						}
+
+					}
+
+				case 'u': // Prefix: "ubmissions/"
+
+					if l := len("ubmissions/"); len(elem) >= l && elem[0:l] == "ubmissions/" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					// Param: "SubmissionID"
+					// Match until "/"
+					idx := strings.IndexByte(elem, '/')
+					if idx < 0 {
+						idx = len(elem)
+					}
+					args[0] = elem[:idx]
+					elem = elem[idx:]
+
+					if len(elem) == 0 {
+						break
+					}
+					switch elem[0] {
+					case '/': // Prefix: "/"
+
+						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							break
+						}
+						switch elem[0] {
+						case 's': // Prefix: "status/validator-"
+
+							if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								break
+							}
+							switch elem[0] {
+							case 'f': // Prefix: "failed"
+
+								if l := len("failed"); len(elem) >= l && elem[0:l] == "failed" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch r.Method {
+									case "POST":
+										s.handleActionSubmissionAcceptedRequest([1]string{
+											args[0],
+										}, elemIsEscaped, w, r)
+									default:
+										s.notAllowed(w, r, "POST")
+									}
+
+									return
+								}
+
+							case 'u': // Prefix: "uploaded"
+
+								if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch r.Method {
+									case "POST":
+										s.handleActionSubmissionUploadedRequest([1]string{
+											args[0],
+										}, elemIsEscaped, w, r)
+									default:
+										s.notAllowed(w, r, "POST")
+									}
+
+									return
+								}
+
+							case 'v': // Prefix: "validated"
+
+								if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch r.Method {
+									case "POST":
+										s.handleActionSubmissionValidatedRequest([1]string{
+											args[0],
+										}, elemIsEscaped, w, r)
+									default:
+										s.notAllowed(w, r, "POST")
+									}
+
+									return
+								}
+
+							}
+
+						case 'v': // Prefix: "validated-model"
+
+							if l := len("validated-model"); len(elem) >= l && elem[0:l] == "validated-model" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch r.Method {
+								case "POST":
+									s.handleUpdateSubmissionValidatedModelRequest([1]string{
+										args[0],
+									}, elemIsEscaped, w, r)
+								default:
+									s.notAllowed(w, r, "POST")
+								}
+
+								return
+							}
+
+						}
+
+					}
+
+				}
+
 			}
 
 		}
@@ -372,9 +525,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 			break
 		}
 		switch elem[0] {
-		case '/': // Prefix: "/s"
+		case '/': // Prefix: "/"
 
-			if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" {
+			if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
 				elem = elem[l:]
 			} else {
 				break
@@ -384,127 +537,15 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 				break
 			}
 			switch elem[0] {
-			case 'c': // Prefix: "cript"
+			case 'm': // Prefix: "mapfixes/"
 
-				if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
+				if l := len("mapfixes/"); len(elem) >= l && elem[0:l] == "mapfixes/" {
 					elem = elem[l:]
 				} else {
 					break
 				}
 
-				if len(elem) == 0 {
-					break
-				}
-				switch elem[0] {
-				case '-': // Prefix: "-policy"
-
-					if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
-						elem = elem[l:]
-					} else {
-						break
-					}
-
-					if len(elem) == 0 {
-						// Leaf node.
-						switch method {
-						case "GET":
-							r.name = ListScriptPolicyOperation
-							r.summary = "Get list of script policies"
-							r.operationID = "listScriptPolicy"
-							r.pathPattern = "/script-policy"
-							r.args = args
-							r.count = 0
-							return r, true
-						case "POST":
-							r.name = CreateScriptPolicyOperation
-							r.summary = "Create a new script policy"
-							r.operationID = "createScriptPolicy"
-							r.pathPattern = "/script-policy"
-							r.args = args
-							r.count = 0
-							return r, true
-						default:
-							return
-						}
-					}
-
-				case 's': // Prefix: "s"
-
-					if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
-						elem = elem[l:]
-					} else {
-						break
-					}
-
-					if len(elem) == 0 {
-						switch method {
-						case "GET":
-							r.name = ListScriptsOperation
-							r.summary = "Get list of scripts"
-							r.operationID = "listScripts"
-							r.pathPattern = "/scripts"
-							r.args = args
-							r.count = 0
-							return r, true
-						case "POST":
-							r.name = CreateScriptOperation
-							r.summary = "Create a new script"
-							r.operationID = "createScript"
-							r.pathPattern = "/scripts"
-							r.args = args
-							r.count = 0
-							return r, true
-						default:
-							return
-						}
-					}
-					switch elem[0] {
-					case '/': // Prefix: "/"
-
-						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
-							elem = elem[l:]
-						} else {
-							break
-						}
-
-						// Param: "ScriptID"
-						// Leaf parameter, slashes are prohibited
-						idx := strings.IndexByte(elem, '/')
-						if idx >= 0 {
-							break
-						}
-						args[0] = elem
-						elem = ""
-
-						if len(elem) == 0 {
-							// Leaf node.
-							switch method {
-							case "GET":
-								r.name = GetScriptOperation
-								r.summary = "Get the specified script by ID"
-								r.operationID = "getScript"
-								r.pathPattern = "/scripts/{ScriptID}"
-								r.args = args
-								r.count = 1
-								return r, true
-							default:
-								return
-							}
-						}
-
-					}
-
-				}
-
-			case 'u': // Prefix: "ubmissions/"
-
-				if l := len("ubmissions/"); len(elem) >= l && elem[0:l] == "ubmissions/" {
-					elem = elem[l:]
-				} else {
-					break
-				}
-
-				// Param: "SubmissionID"
+				// Param: "MapfixID"
 				// Match until "/"
 				idx := strings.IndexByte(elem, '/')
 				if idx < 0 {
@@ -553,10 +594,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 								// Leaf node.
 								switch method {
 								case "POST":
-									r.name = ActionSubmissionAcceptedOperation
+									r.name = ActionMapfixAcceptedOperation
 									r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Accepted"
-									r.operationID = "actionSubmissionAccepted"
-									r.pathPattern = "/submissions/{SubmissionID}/status/validator-failed"
+									r.operationID = "actionMapfixAccepted"
+									r.pathPattern = "/mapfixes/{MapfixID}/status/validator-failed"
 									r.args = args
 									r.count = 1
 									return r, true
@@ -577,10 +618,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 								// Leaf node.
 								switch method {
 								case "POST":
-									r.name = ActionSubmissionUploadedOperation
+									r.name = ActionMapfixUploadedOperation
 									r.summary = "(Internal endpoint) Role Validator changes status from Uploading -> Uploaded"
-									r.operationID = "actionSubmissionUploaded"
-									r.pathPattern = "/submissions/{SubmissionID}/status/validator-uploaded"
+									r.operationID = "actionMapfixUploaded"
+									r.pathPattern = "/mapfixes/{MapfixID}/status/validator-uploaded"
 									r.args = args
 									r.count = 1
 									return r, true
@@ -601,10 +642,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 								// Leaf node.
 								switch method {
 								case "POST":
-									r.name = ActionSubmissionValidatedOperation
+									r.name = ActionMapfixValidatedOperation
 									r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Validated"
-									r.operationID = "actionSubmissionValidated"
-									r.pathPattern = "/submissions/{SubmissionID}/status/validator-validated"
+									r.operationID = "actionMapfixValidated"
+									r.pathPattern = "/mapfixes/{MapfixID}/status/validator-validated"
 									r.args = args
 									r.count = 1
 									return r, true
@@ -627,10 +668,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 							// Leaf node.
 							switch method {
 							case "POST":
-								r.name = UpdateSubmissionValidatedModelOperation
+								r.name = UpdateMapfixValidatedModelOperation
 								r.summary = "Update validated model"
-								r.operationID = "updateSubmissionValidatedModel"
-								r.pathPattern = "/submissions/{SubmissionID}/validated-model"
+								r.operationID = "updateMapfixValidatedModel"
+								r.pathPattern = "/mapfixes/{MapfixID}/validated-model"
 								r.args = args
 								r.count = 1
 								return r, true
@@ -643,6 +684,279 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 
 				}
 
+			case 's': // Prefix: "s"
+
+				if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
+					elem = elem[l:]
+				} else {
+					break
+				}
+
+				if len(elem) == 0 {
+					break
+				}
+				switch elem[0] {
+				case 'c': // Prefix: "cript"
+
+					if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					if len(elem) == 0 {
+						break
+					}
+					switch elem[0] {
+					case '-': // Prefix: "-policy"
+
+						if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							// Leaf node.
+							switch method {
+							case "GET":
+								r.name = ListScriptPolicyOperation
+								r.summary = "Get list of script policies"
+								r.operationID = "listScriptPolicy"
+								r.pathPattern = "/script-policy"
+								r.args = args
+								r.count = 0
+								return r, true
+							case "POST":
+								r.name = CreateScriptPolicyOperation
+								r.summary = "Create a new script policy"
+								r.operationID = "createScriptPolicy"
+								r.pathPattern = "/script-policy"
+								r.args = args
+								r.count = 0
+								return r, true
+							default:
+								return
+							}
+						}
+
+					case 's': // Prefix: "s"
+
+						if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							switch method {
+							case "GET":
+								r.name = ListScriptsOperation
+								r.summary = "Get list of scripts"
+								r.operationID = "listScripts"
+								r.pathPattern = "/scripts"
+								r.args = args
+								r.count = 0
+								return r, true
+							case "POST":
+								r.name = CreateScriptOperation
+								r.summary = "Create a new script"
+								r.operationID = "createScript"
+								r.pathPattern = "/scripts"
+								r.args = args
+								r.count = 0
+								return r, true
+							default:
+								return
+							}
+						}
+						switch elem[0] {
+						case '/': // Prefix: "/"
+
+							if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							// Param: "ScriptID"
+							// Leaf parameter, slashes are prohibited
+							idx := strings.IndexByte(elem, '/')
+							if idx >= 0 {
+								break
+							}
+							args[0] = elem
+							elem = ""
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch method {
+								case "GET":
+									r.name = GetScriptOperation
+									r.summary = "Get the specified script by ID"
+									r.operationID = "getScript"
+									r.pathPattern = "/scripts/{ScriptID}"
+									r.args = args
+									r.count = 1
+									return r, true
+								default:
+									return
+								}
+							}
+
+						}
+
+					}
+
+				case 'u': // Prefix: "ubmissions/"
+
+					if l := len("ubmissions/"); len(elem) >= l && elem[0:l] == "ubmissions/" {
+						elem = elem[l:]
+					} else {
+						break
+					}
+
+					// Param: "SubmissionID"
+					// Match until "/"
+					idx := strings.IndexByte(elem, '/')
+					if idx < 0 {
+						idx = len(elem)
+					}
+					args[0] = elem[:idx]
+					elem = elem[idx:]
+
+					if len(elem) == 0 {
+						break
+					}
+					switch elem[0] {
+					case '/': // Prefix: "/"
+
+						if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
+							elem = elem[l:]
+						} else {
+							break
+						}
+
+						if len(elem) == 0 {
+							break
+						}
+						switch elem[0] {
+						case 's': // Prefix: "status/validator-"
+
+							if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								break
+							}
+							switch elem[0] {
+							case 'f': // Prefix: "failed"
+
+								if l := len("failed"); len(elem) >= l && elem[0:l] == "failed" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch method {
+									case "POST":
+										r.name = ActionSubmissionAcceptedOperation
+										r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Accepted"
+										r.operationID = "actionSubmissionAccepted"
+										r.pathPattern = "/submissions/{SubmissionID}/status/validator-failed"
+										r.args = args
+										r.count = 1
+										return r, true
+									default:
+										return
+									}
+								}
+
+							case 'u': // Prefix: "uploaded"
+
+								if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch method {
+									case "POST":
+										r.name = ActionSubmissionUploadedOperation
+										r.summary = "(Internal endpoint) Role Validator changes status from Uploading -> Uploaded"
+										r.operationID = "actionSubmissionUploaded"
+										r.pathPattern = "/submissions/{SubmissionID}/status/validator-uploaded"
+										r.args = args
+										r.count = 1
+										return r, true
+									default:
+										return
+									}
+								}
+
+							case 'v': // Prefix: "validated"
+
+								if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" {
+									elem = elem[l:]
+								} else {
+									break
+								}
+
+								if len(elem) == 0 {
+									// Leaf node.
+									switch method {
+									case "POST":
+										r.name = ActionSubmissionValidatedOperation
+										r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Validated"
+										r.operationID = "actionSubmissionValidated"
+										r.pathPattern = "/submissions/{SubmissionID}/status/validator-validated"
+										r.args = args
+										r.count = 1
+										return r, true
+									default:
+										return
+									}
+								}
+
+							}
+
+						case 'v': // Prefix: "validated-model"
+
+							if l := len("validated-model"); len(elem) >= l && elem[0:l] == "validated-model" {
+								elem = elem[l:]
+							} else {
+								break
+							}
+
+							if len(elem) == 0 {
+								// Leaf node.
+								switch method {
+								case "POST":
+									r.name = UpdateSubmissionValidatedModelOperation
+									r.summary = "Update validated model"
+									r.operationID = "updateSubmissionValidatedModel"
+									r.pathPattern = "/submissions/{SubmissionID}/validated-model"
+									r.args = args
+									r.count = 1
+									return r, true
+								default:
+									return
+								}
+							}
+
+						}
+
+					}
+
+				}
+
 			}
 
 		}
diff --git a/pkg/internal/oas_schemas_gen.go b/pkg/internal/oas_schemas_gen.go
index 4805a04..2f06835 100644
--- a/pkg/internal/oas_schemas_gen.go
+++ b/pkg/internal/oas_schemas_gen.go
@@ -10,6 +10,15 @@ func (s *ErrorStatusCode) Error() string {
 	return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response)
 }
 
+// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
+type ActionMapfixAcceptedNoContent struct{}
+
+// ActionMapfixUploadedNoContent is response for ActionMapfixUploaded operation.
+type ActionMapfixUploadedNoContent struct{}
+
+// ActionMapfixValidatedNoContent is response for ActionMapfixValidated operation.
+type ActionMapfixValidatedNoContent struct{}
+
 // ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
 type ActionSubmissionAcceptedNoContent struct{}
 
@@ -428,5 +437,8 @@ func (s *ScriptPolicyCreate) SetPolicy(val int32) {
 	s.Policy = val
 }
 
+// UpdateMapfixValidatedModelNoContent is response for UpdateMapfixValidatedModel operation.
+type UpdateMapfixValidatedModelNoContent struct{}
+
 // UpdateSubmissionValidatedModelNoContent is response for UpdateSubmissionValidatedModel operation.
 type UpdateSubmissionValidatedModelNoContent struct{}
diff --git a/pkg/internal/oas_server_gen.go b/pkg/internal/oas_server_gen.go
index 1221cb6..846550e 100644
--- a/pkg/internal/oas_server_gen.go
+++ b/pkg/internal/oas_server_gen.go
@@ -8,6 +8,24 @@ import (
 
 // Handler handles operations described by OpenAPI v3 specification.
 type Handler interface {
+	// ActionMapfixAccepted implements actionMapfixAccepted operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-failed
+	ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
+	// ActionMapfixUploaded implements actionMapfixUploaded operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-uploaded
+	ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error
+	// ActionMapfixValidated implements actionMapfixValidated operation.
+	//
+	// (Internal endpoint) Role Validator changes status from Validating -> Validated.
+	//
+	// POST /mapfixes/{MapfixID}/status/validator-validated
+	ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
 	// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
 	//
 	// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
@@ -56,6 +74,12 @@ type Handler interface {
 	//
 	// GET /scripts
 	ListScripts(ctx context.Context, params ListScriptsParams) ([]Script, error)
+	// UpdateMapfixValidatedModel implements updateMapfixValidatedModel operation.
+	//
+	// Update validated model.
+	//
+	// POST /mapfixes/{MapfixID}/validated-model
+	UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error
 	// UpdateSubmissionValidatedModel implements updateSubmissionValidatedModel operation.
 	//
 	// Update validated model.
diff --git a/pkg/internal/oas_unimplemented_gen.go b/pkg/internal/oas_unimplemented_gen.go
index 7d7f09d..1a08c02 100644
--- a/pkg/internal/oas_unimplemented_gen.go
+++ b/pkg/internal/oas_unimplemented_gen.go
@@ -13,6 +13,33 @@ type UnimplementedHandler struct{}
 
 var _ Handler = UnimplementedHandler{}
 
+// ActionMapfixAccepted implements actionMapfixAccepted operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/validator-failed
+func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixUploaded implements actionMapfixUploaded operation.
+//
+// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+//
+// POST /mapfixes/{MapfixID}/status/validator-uploaded
+func (UnimplementedHandler) ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error {
+	return ht.ErrNotImplemented
+}
+
+// ActionMapfixValidated implements actionMapfixValidated operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/validator-validated
+func (UnimplementedHandler) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
+	return ht.ErrNotImplemented
+}
+
 // ActionSubmissionAccepted implements actionSubmissionAccepted operation.
 //
 // (Internal endpoint) Role Validator changes status from Validating -> Accepted.
@@ -85,6 +112,15 @@ func (UnimplementedHandler) ListScripts(ctx context.Context, params ListScriptsP
 	return r, ht.ErrNotImplemented
 }
 
+// UpdateMapfixValidatedModel implements updateMapfixValidatedModel operation.
+//
+// Update validated model.
+//
+// POST /mapfixes/{MapfixID}/validated-model
+func (UnimplementedHandler) UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error {
+	return ht.ErrNotImplemented
+}
+
 // UpdateSubmissionValidatedModel implements updateSubmissionValidatedModel operation.
 //
 // Update validated model.
-- 
2.47.1


From 732598266cae21825e7e9fd0827d5a563309f722 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Tue, 1 Apr 2025 13:32:37 -0700
Subject: [PATCH 4/7] submissions: mapfixes

---
 pkg/model/mapfix.go              |  37 ++
 pkg/model/nats.go                |   7 +
 pkg/service/mapfixes.go          | 598 +++++++++++++++++++++++++++++++
 pkg/service_internal/mapfixes.go |  61 ++++
 4 files changed, 703 insertions(+)
 create mode 100644 pkg/model/mapfix.go
 create mode 100644 pkg/service/mapfixes.go
 create mode 100644 pkg/service_internal/mapfixes.go

diff --git a/pkg/model/mapfix.go b/pkg/model/mapfix.go
new file mode 100644
index 0000000..09e254a
--- /dev/null
+++ b/pkg/model/mapfix.go
@@ -0,0 +1,37 @@
+package model
+
+import "time"
+
+type MapfixStatus int32
+
+const (
+	// Phase: Final MapfixStatus
+	MapfixStatusRejected  MapfixStatus = 8
+	MapfixStatusUploaded   MapfixStatus = 7 // uploaded to the group, final status for mapfixes
+
+	// Phase: Testing
+	MapfixStatusUploading  MapfixStatus = 6
+	MapfixStatusValidated  MapfixStatus = 5
+	MapfixStatusValidating MapfixStatus = 4
+	MapfixStatusAccepted   MapfixStatus = 3 // pending script review, can re-trigger validation
+
+	// Phase: Creation
+	MapfixStatusChangesRequested  MapfixStatus = 2
+	MapfixStatusSubmitted         MapfixStatus = 1
+	MapfixStatusUnderConstruction MapfixStatus = 0
+)
+
+type Mapfix struct {
+	ID            int64 `gorm:"primaryKey"`
+	CreatedAt     time.Time
+	UpdatedAt     time.Time
+	Submitter     int64 // UserID
+	AssetID       int64
+	AssetVersion  int64
+	ValidatedAssetID       int64
+	ValidatedAssetVersion  int64
+	Completed     bool   // Has this version of the map been completed at least once on maptest
+	TargetAssetID int64 // where to upload map fix.  if the TargetAssetID is 0, it's a new map.
+	StatusID      MapfixStatus
+	StatusMessage string
+}
diff --git a/pkg/model/nats.go b/pkg/model/nats.go
index 60114b0..6add04f 100644
--- a/pkg/model/nats.go
+++ b/pkg/model/nats.go
@@ -13,6 +13,13 @@ type ValidateSubmissionRequest struct {
 	ValidatedModelID *int64 // optional value
 }
 
+type ValidateMapfixRequest struct {
+	MapfixID     int64
+	ModelID          int64
+	ModelVersion     int64
+	ValidatedModelID *int64 // optional value
+}
+
 // Create a new map
 type UploadSubmissionRequest struct {
 	SubmissionID int64
diff --git a/pkg/service/mapfixes.go b/pkg/service/mapfixes.go
new file mode 100644
index 0000000..f318661
--- /dev/null
+++ b/pkg/service/mapfixes.go
@@ -0,0 +1,598 @@
+package service
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"time"
+
+	"git.itzana.me/strafesnet/maps-service/pkg/api"
+	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
+	"git.itzana.me/strafesnet/maps-service/pkg/model"
+)
+
+var(
+	CreationPhaseMapfixesLimit = 20
+	CreationPhaseMapfixStatuses = []model.MapfixStatus{
+		model.MapfixStatusChangesRequested,
+		model.MapfixStatusSubmitted,
+		model.MapfixStatusUnderConstruction,
+	}
+	// prevent two mapfixes with same asset id
+	ActiveMapfixStatuses = []model.MapfixStatus{
+		model.MapfixStatusUploading,
+		model.MapfixStatusValidated,
+		model.MapfixStatusValidating,
+		model.MapfixStatusAccepted,
+		model.MapfixStatusChangesRequested,
+		model.MapfixStatusSubmitted,
+		model.MapfixStatusUnderConstruction,
+	}
+	// limit mapfixes in the pipeline to one per target map
+	ActiveAcceptedMapfixStatuses = []model.MapfixStatus{
+		model.MapfixStatusUploading,
+		model.MapfixStatusValidated,
+		model.MapfixStatusValidating,
+		model.MapfixStatusAccepted,
+	}
+)
+
+var (
+	ErrCreationPhaseMapfixesLimit = errors.New("Active mapfixes limited to 20")
+	ErrActiveMapfixSameAssetID = errors.New("There is an active mapfix with the same AssetID")
+	ErrActiveMapfixSameTargetAssetID = errors.New("There is an active mapfix with the same TargetAssetID")
+	ErrAcceptOwnMapfix = fmt.Errorf("%w: You cannot accept your own mapfix as the submitter", ErrPermissionDenied)
+)
+
+// POST /mapfixes
+func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixCreate) (*api.ID, error) {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return nil, ErrUserInfo
+	}
+
+	userId, err := userInfo.GetUserID()
+	if err != nil {
+		return nil, err
+	}
+
+	// Check if user's mapfixes in the creation phase exceeds the limit
+	{
+		filter := datastore.Optional()
+		filter.Add("submitter", int64(userId))
+		filter.Add("status_id", CreationPhaseMapfixStatuses)
+		creation_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   int32(CreationPhaseMapfixesLimit),
+		},datastore.ListSortDisabled)
+		if err != nil {
+			return nil, err
+		}
+
+		if CreationPhaseMapfixesLimit <= len(creation_mapfixes) {
+			return nil, ErrCreationPhaseMapfixesLimit
+		}
+	}
+
+	// Check if an active mapfix with the same asset id exists
+	{
+		filter := datastore.Optional()
+		filter.Add("asset_id", request.AssetID)
+		filter.Add("asset_version", request.AssetVersion)
+		filter.Add("status_id", ActiveMapfixStatuses)
+		active_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   1,
+		},datastore.ListSortDisabled)
+		if err != nil {
+			return nil, err
+		}
+		if len(active_mapfixes) != 0{
+			return nil, ErrActiveMapfixSameAssetID
+		}
+	}
+
+	mapfix, err := svc.DB.Mapfixes().Create(ctx, model.Mapfix{
+		ID:            0,
+		Submitter:     int64(userId),
+		AssetID:       request.AssetID,
+		AssetVersion:  request.AssetVersion,
+		Completed:     false,
+		TargetAssetID: request.TargetAssetID,
+		StatusID:      model.MapfixStatusUnderConstruction,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &api.ID{
+		ID: mapfix.ID,
+	}, nil
+}
+
+// GetMapfix implements getMapfix operation.
+//
+// Retrieve map with ID.
+//
+// GET /mapfixes/{MapfixID}
+func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (*api.Mapfix, error) {
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return nil, err
+	}
+	return &api.Mapfix{
+		ID:            mapfix.ID,
+		CreatedAt:     mapfix.CreatedAt.Unix(),
+		UpdatedAt:     mapfix.UpdatedAt.Unix(),
+		Submitter:     int64(mapfix.Submitter),
+		AssetID:       int64(mapfix.AssetID),
+		AssetVersion:  int64(mapfix.AssetVersion),
+		Completed:     mapfix.Completed,
+		TargetAssetID: int64(mapfix.TargetAssetID),
+		StatusID:      int32(mapfix.StatusID),
+		StatusMessage: mapfix.StatusMessage,
+	}, nil
+}
+
+// ListMapfixes implements listMapfixes operation.
+//
+// Get list of mapfixes.
+//
+// GET /mapfixes
+func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) ([]api.Mapfix, error) {
+	filter := datastore.Optional()
+
+	sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
+
+	items, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
+		Number: params.Page,
+		Size:   params.Limit,
+	},sort)
+	if err != nil {
+		return nil, err
+	}
+
+	var resp []api.Mapfix
+	for _, item := range items {
+		resp = append(resp, api.Mapfix{
+			ID:            item.ID,
+			CreatedAt:     item.CreatedAt.Unix(),
+			UpdatedAt:     item.UpdatedAt.Unix(),
+			Submitter:     int64(item.Submitter),
+			AssetID:       int64(item.AssetID),
+			AssetVersion:  int64(item.AssetVersion),
+			Completed:     item.Completed,
+			TargetAssetID: int64(item.TargetAssetID),
+			StatusID:      int32(item.StatusID),
+		})
+	}
+
+	return resp, nil
+}
+
+// PatchMapfixCompleted implements patchMapfixCompleted operation.
+//
+// Retrieve map with ID.
+//
+// POST /mapfixes/{MapfixID}/completed
+func (svc *Service) SetMapfixCompleted(ctx context.Context, params api.SetMapfixCompletedParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMaptest()
+	if err != nil {
+		return err
+	}
+	// check if caller has MaptestGame role (request must originate from a maptest roblox game)
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMaptest
+	}
+
+	pmap := datastore.Optional()
+	pmap.Add("completed", true)
+	return svc.DB.Mapfixes().Update(ctx, params.MapfixID, pmap)
+}
+
+// UpdateMapfixModel implements patchMapfixModel operation.
+//
+// Update model following role restrictions.
+//
+// POST /mapfixes/{MapfixID}/model
+func (svc *Service) UpdateMapfixModel(ctx context.Context, params api.UpdateMapfixModelParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	// read mapfix (this could be done with a transaction WHERE clause)
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+
+	has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
+	if err != nil {
+		return err
+	}
+	// check if caller is the submitter
+	if !has_role {
+		return ErrPermissionDeniedNotSubmitter
+	}
+
+	// check if Status is ChangesRequested|Submitted|UnderConstruction
+	pmap := datastore.Optional()
+	pmap.AddNotNil("asset_id", params.ModelID)
+	pmap.AddNotNil("asset_version", params.VersionID)
+	//always reset completed when model changes
+	pmap.Add("completed", false)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
+}
+
+// ActionMapfixReject invokes actionMapfixReject operation.
+//
+// Role Reviewer changes status from Submitted -> Rejected.
+//
+// POST /mapfixes/{MapfixID}/status/reject
+func (svc *Service) ActionMapfixReject(ctx context.Context, params api.ActionMapfixRejectParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixReview()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapReview
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusRejected)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
+}
+
+// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
+//
+// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
+//
+// POST /mapfixes/{MapfixID}/status/request-changes
+func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params api.ActionMapfixRequestChangesParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixReview()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapReview
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusChangesRequested)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAccepted, model.MapfixStatusSubmitted}, smap)
+}
+
+// ActionMapfixRevoke invokes actionMapfixRevoke operation.
+//
+// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
+//
+// POST /mapfixes/{MapfixID}/status/revoke
+func (svc *Service) ActionMapfixRevoke(ctx context.Context, params api.ActionMapfixRevokeParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	// read mapfix (this could be done with a transaction WHERE clause)
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+
+	has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
+	if err != nil {
+		return err
+	}
+	// check if caller is the submitter
+	if !has_role {
+		return ErrPermissionDeniedNotSubmitter
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusUnderConstruction)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap)
+}
+
+// ActionMapfixSubmit invokes actionMapfixSubmit operation.
+//
+// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
+//
+// POST /mapfixes/{MapfixID}/status/submit
+func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMapfixSubmitParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	// read mapfix (this could be done with a transaction WHERE clause)
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+
+	has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
+	if err != nil {
+		return err
+	}
+	// check if caller is the submitter
+	if !has_role {
+		return ErrPermissionDeniedNotSubmitter
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusSubmitted)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
+}
+
+// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
+//
+// Role Admin changes status from Validated -> Uploading.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-upload
+func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.ActionMapfixTriggerUploadParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixUpload()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapUpload
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusUploading)
+	mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated}, smap)
+	if err != nil {
+		return err
+	}
+
+	// this is a map fix
+	upload_fix_request := model.UploadMapfixRequest{
+		MapfixID:      mapfix.ID,
+		ModelID:       mapfix.ValidatedAssetID,
+		ModelVersion:  mapfix.ValidatedAssetVersion,
+		TargetAssetID: mapfix.TargetAssetID,
+	}
+
+	j, err := json.Marshal(upload_fix_request)
+	if err != nil {
+		return err
+	}
+
+	svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j))
+
+	return nil
+}
+
+// ActionMapfixValidate invokes actionMapfixValidate operation.
+//
+// Role MapfixRelease changes status from Uploading -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/reset-uploading
+func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.ActionMapfixValidatedParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixUpload()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapUpload
+	}
+
+	// check when mapfix was updated
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+	if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
+		// the last time the mapfix was updated must be longer than 10 seconds ago
+		return ErrDelayReset
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusValidated)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
+}
+
+// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
+//
+// Role Reviewer triggers validation and changes status from Submitted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/trigger-validate
+func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.ActionMapfixTriggerValidateParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixReview()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapReview
+	}
+
+	// read mapfix (this could be done with a transaction WHERE clause)
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+
+	has_role, err = userInfo.IsSubmitter(uint64(mapfix.Submitter))
+	if err != nil {
+		return err
+	}
+	// check if caller is NOT the submitter
+	if has_role {
+		return ErrAcceptOwnMapfix
+	}
+
+	// Check if an active mapfix with the same target asset id exists
+	if mapfix.TargetAssetID != 0 {
+		filter := datastore.Optional()
+		filter.Add("target_asset_id", mapfix.TargetAssetID)
+		filter.Add("status_id", ActiveAcceptedMapfixStatuses)
+		active_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
+			Number: 1,
+			Size:   1,
+		},datastore.ListSortDisabled)
+		if err != nil {
+			return err
+		}
+		if len(active_mapfixes) != 0{
+			return ErrActiveMapfixSameTargetAssetID
+		}
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusValidating)
+	mapfix, err = svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
+	if err != nil {
+		return err
+	}
+
+	validate_request := model.ValidateMapfixRequest{
+		MapfixID:         mapfix.ID,
+		ModelID:          mapfix.AssetID,
+		ModelVersion:     mapfix.AssetVersion,
+		ValidatedModelID: nil,
+	}
+
+	// sentinel values because we're not using rust
+	if mapfix.ValidatedAssetID != 0 {
+		validate_request.ValidatedModelID = &mapfix.ValidatedAssetID
+	}
+
+	j, err := json.Marshal(validate_request)
+	if err != nil {
+		return err
+	}
+
+	svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
+
+	return nil
+}
+
+// ActionMapfixRetryValidate invokes actionMapfixRetryValidate operation.
+//
+// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
+//
+// POST /mapfixes/{MapfixID}/status/retry-validate
+func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.ActionMapfixRetryValidateParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixReview()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapReview
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusValidating)
+	mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAccepted}, smap)
+	if err != nil {
+		return err
+	}
+
+	validate_request := model.ValidateMapfixRequest{
+		MapfixID:     mapfix.ID,
+		ModelID:          mapfix.AssetID,
+		ModelVersion:     mapfix.AssetVersion,
+		ValidatedModelID: nil,
+	}
+
+	// sentinel values because we're not using rust
+	if mapfix.ValidatedAssetID != 0 {
+		validate_request.ValidatedModelID = &mapfix.ValidatedAssetID
+	}
+
+	j, err := json.Marshal(validate_request)
+	if err != nil {
+		return err
+	}
+
+	svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
+
+	return nil
+}
+
+// ActionMapfixAccepted implements actionMapfixAccepted operation.
+//
+// Role MapfixReview changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/reset-validating
+func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionMapfixAcceptedParams) error {
+	userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
+	if !ok {
+		return ErrUserInfo
+	}
+
+	has_role, err := userInfo.HasRoleMapfixReview()
+	if err != nil {
+		return err
+	}
+	// check if caller has required role
+	if !has_role {
+		return ErrPermissionDeniedNeedRoleMapReview
+	}
+
+	// check when mapfix was updated
+	mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
+	if err != nil {
+		return err
+	}
+	if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
+		// the last time the mapfix was updated must be longer than 10 seconds ago
+		return ErrDelayReset
+	}
+
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusAccepted)
+	smap.Add("status_message", "Manually forced reset")
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
+}
diff --git a/pkg/service_internal/mapfixes.go b/pkg/service_internal/mapfixes.go
new file mode 100644
index 0000000..cfdf31a
--- /dev/null
+++ b/pkg/service_internal/mapfixes.go
@@ -0,0 +1,61 @@
+package service_internal
+
+import (
+	"context"
+
+	internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
+	"git.itzana.me/strafesnet/maps-service/pkg/datastore"
+	"git.itzana.me/strafesnet/maps-service/pkg/model"
+)
+
+// UpdateMapfixValidatedModel implements patchMapfixModel operation.
+//
+// Update model following role restrictions.
+//
+// POST /mapfixes/{MapfixID}/validated-model
+func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
+	// check if Status is ChangesRequested|Submitted|UnderConstruction
+	pmap := datastore.Optional()
+	pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
+	pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
+	// DO NOT reset completed when validated model is updated
+	// pmap.Add("completed", false)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
+}
+
+// ActionMapfixValidate invokes actionMapfixValidate operation.
+//
+// Role Validator changes status from Validating -> Validated.
+//
+// POST /mapfixes/{MapfixID}/status/validator-validated
+func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.ActionMapfixValidatedParams) error {
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusValidated)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
+}
+
+// ActionMapfixAccepted implements actionMapfixAccepted operation.
+//
+// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
+//
+// POST /mapfixes/{MapfixID}/status/validator-failed
+func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusAccepted)
+	smap.Add("status_message", params.StatusMessage)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
+}
+
+// ActionMapfixUploaded implements actionMapfixUploaded operation.
+//
+// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
+//
+// POST /mapfixes/{MapfixID}/status/validator-uploaded
+func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
+	// transaction
+	smap := datastore.Optional()
+	smap.Add("status_id", model.MapfixStatusUploaded)
+	return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
+}
-- 
2.47.1


From cc7df064bea978b29bc94bfda8a7c17bff85c7c5 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Tue, 1 Apr 2025 13:19:17 -0700
Subject: [PATCH 5/7] submissions-api: deduplicate simple endpoints with crazy
 macro

---
 validation/api/src/internal.rs | 81 +++++++++++++---------------------
 1 file changed, 31 insertions(+), 50 deletions(-)

diff --git a/validation/api/src/internal.rs b/validation/api/src/internal.rs
index 990466d..0086767 100644
--- a/validation/api/src/internal.rs
+++ b/validation/api/src/internal.rs
@@ -3,12 +3,27 @@ use crate::types::*;
 #[derive(Clone)]
 pub struct Context(crate::context::Context);
 
+// conditionally include specified query pairs
+macro_rules! query_pairs{
+	($url:expr,)=>{
+		$url
+	};
+	($url:expr,$(($param:expr,$value:expr))+)=>{
+		{
+			let mut url=$url;
+			url.query_pairs_mut()
+				$(.append_pair($param,$value))*;
+			url
+		}
+	};
+}
+
 // there are lots of action endpoints and they all follow the same pattern
 macro_rules! action{
-	($fname:ident,$action:expr)=>{
-		pub async fn $fname(&self,config:SubmissionID)->Result<(),Error>{
-			let url_raw=format!(concat!("{}/submissions/{}/status/",$action),self.0.base_url,config.0);
-			let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
+	($system:expr,$fname:ident,$config:ident,$config_type:ident,$action:expr,$config_submission_id:expr,$(($param:expr,$value:expr))*)=>{
+		pub async fn $fname(&self,$config:$config_type)->Result<(),Error>{
+			let url_raw=format!(concat!("{}/",$system,"/{}/status/",$action),self.0.base_url,$config_submission_id);
+			let url=query_pairs!(reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?,$(($param,$value))*);
 
 			response_ok(
 				self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
@@ -135,50 +150,16 @@ impl Context{
 		).await.map_err(Error::Response)?
 		.json().await.map_err(Error::ReqwestJson)
 	}
-	pub async fn update_submission_validated_model(&self,config:UpdateSubmissionModelRequest)->Result<(),Error>{
-		let url_raw=format!("{}/submissions/{}/validated-model",self.0.base_url,config.SubmissionID);
-		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
-
-		{
-			url.query_pairs_mut()
-				.append_pair("ValidatedModelID",config.ModelID.to_string().as_str())
-				.append_pair("ValidatedModelVersion",config.ModelVersion.to_string().as_str());
-		}
-
-		response_ok(
-			self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
-		).await.map_err(Error::Response)?;
-
-		Ok(())
-	}
-	pub async fn action_submission_uploaded(&self,config:ActionSubmissionUploadedRequest)->Result<(),Error>{
-		let url_raw=format!("{}/submissions/{}/status/validator-uploaded",self.0.base_url,config.SubmissionID);
-		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
-
-		{
-			url.query_pairs_mut()
-				.append_pair("UploadedAssetID",config.UploadedAssetID.to_string().as_str());
-		}
-		response_ok(
-			self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
-		).await.map_err(Error::Response)?;
-
-		Ok(())
-	}
-	pub async fn action_submission_accepted(&self,config:ActionSubmissionAcceptedRequest)->Result<(),Error>{
-		let url_raw=format!("{}/submissions/{}/status/validator-failed",self.0.base_url,config.SubmissionID);
-		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
-
-		{
-			url.query_pairs_mut()
-				.append_pair("StatusMessage",config.StatusMessage.as_str());
-		}
-
-		response_ok(
-			self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
-		).await.map_err(Error::Response)?;
-
-		Ok(())
-	}
-	action!(action_submission_validated,"validator-validated");
+	// simple submission endpoints
+	action!("submissions",action_submission_validated,config,SubmissionID,"validator-validated",config.0,);
+	action!("submissions",update_submission_validated_model,config,UpdateSubmissionModelRequest,"validated-model",config.SubmissionID,
+		("ValidatedModelID",config.ModelID.to_string().as_str())
+		("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
+	);
+	action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"validator-uploaded",config.SubmissionID,
+		("UploadedAssetID",config.UploadedAssetID.to_string().as_str())
+	);
+	action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"validator-failed",config.SubmissionID,
+		("StatusMessage",config.StatusMessage.as_str())
+	);
 }
-- 
2.47.1


From 9dd7a41d8faebd9a5bc9f19ab4046907cba97493 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Tue, 1 Apr 2025 13:19:26 -0700
Subject: [PATCH 6/7] submissions-api: add simple mapfixes endpoints

---
 validation/api/src/internal.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/validation/api/src/internal.rs b/validation/api/src/internal.rs
index 0086767..9897f9f 100644
--- a/validation/api/src/internal.rs
+++ b/validation/api/src/internal.rs
@@ -162,4 +162,14 @@ impl Context{
 	action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"validator-failed",config.SubmissionID,
 		("StatusMessage",config.StatusMessage.as_str())
 	);
+	// simple mapfixes endpoints
+	action!("mapfixes",action_mapfix_validated,config,MapfixID,"validator-validated",config.0,);
+	action!("mapfixes",update_mapfix_validated_model,config,UpdateMapfixModelRequest,"validated-model",config.MapfixID,
+		("ValidatedModelID",config.ModelID.to_string().as_str())
+		("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
+	);
+	action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"validator-uploaded",config.MapfixID,);
+	action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"validator-failed",config.MapfixID,
+		("StatusMessage",config.StatusMessage.as_str())
+	);
 }
-- 
2.47.1


From 96ace736f46c1299bb9704b9600e4ef4e08434bf Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 31 Mar 2025 18:28:21 -0700
Subject: [PATCH 7/7] validator: add mapfix capability

---
 validation/api/src/types.rs       | 24 ++++++++++++++++++++++++
 validation/src/main.rs            |  2 ++
 validation/src/message_handler.rs |  8 ++++++++
 validation/src/nats_types.rs      |  9 +++++++++
 validation/src/validator.rs       | 10 +++++++---
 5 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/validation/api/src/types.rs b/validation/api/src/types.rs
index 60d1f4c..6cdd357 100644
--- a/validation/api/src/types.rs
+++ b/validation/api/src/types.rs
@@ -202,3 +202,27 @@ pub struct ActionSubmissionAcceptedRequest{
 
 #[derive(Clone,Copy,Debug)]
 pub struct SubmissionID(pub i64);
+
+#[allow(nonstandard_style)]
+#[derive(Clone,Debug)]
+pub struct UpdateMapfixModelRequest{
+	pub MapfixID:i64,
+	pub ModelID:u64,
+	pub ModelVersion:u64,
+}
+
+#[allow(nonstandard_style)]
+#[derive(Clone,Debug)]
+pub struct ActionMapfixUploadedRequest{
+	pub MapfixID:i64,
+}
+
+#[allow(nonstandard_style)]
+#[derive(Clone,Debug)]
+pub struct ActionMapfixAcceptedRequest{
+	pub MapfixID:i64,
+	pub StatusMessage:String,
+}
+
+#[derive(Clone,Copy,Debug)]
+pub struct MapfixID(pub i64);
diff --git a/validation/src/main.rs b/validation/src/main.rs
index 681e529..9234aa8 100644
--- a/validation/src/main.rs
+++ b/validation/src/main.rs
@@ -4,8 +4,10 @@ mod message_handler;
 mod nats_types;
 mod types;
 mod uploader;
+mod upload_mapfix;
 mod upload_submission;
 mod validator;
+mod validate_mapfix;
 mod validate_submission;
 
 #[allow(dead_code)]
diff --git a/validation/src/message_handler.rs b/validation/src/message_handler.rs
index 3b7bdb8..c6cd200 100644
--- a/validation/src/message_handler.rs
+++ b/validation/src/message_handler.rs
@@ -5,7 +5,9 @@ pub enum HandleMessageError{
 	DoubleAck(async_nats::Error),
 	Json(serde_json::Error),
 	UnknownSubject(String),
+	UploadMapfix(crate::upload_mapfix::UploadError),
 	UploadSubmission(crate::upload_submission::UploadError),
+	ValidateMapfix(crate::validate_mapfix::ValidateMapfixError),
 	ValidateSubmission(crate::validate_submission::ValidateSubmissionError),
 }
 impl std::fmt::Display for HandleMessageError{
@@ -22,7 +24,9 @@ fn from_slice<'a,T:serde::de::Deserialize<'a>>(slice:&'a [u8])->Result<T,HandleM
 }
 
 pub struct MessageHandler{
+	upload_mapfix:crate::upload_mapfix::Uploader,
 	upload_submission:crate::upload_submission::Uploader,
+	validate_mapfix:crate::validate_mapfix::Validator,
 	validate_submission:crate::validate_submission::Validator,
 }
 
@@ -33,7 +37,9 @@ impl MessageHandler{
 		api:submissions_api::internal::Context,
 	)->Self{
 		Self{
+			upload_mapfix:crate::upload_mapfix::Uploader::new(crate::uploader::Uploader::new(cookie_context.clone(),group_id,api.clone())),
 			upload_submission:crate::upload_submission::Uploader::new(crate::uploader::Uploader::new(cookie_context.clone(),group_id,api.clone())),
+			validate_mapfix:crate::validate_mapfix::Validator::new(crate::validator::Validator::new(cookie_context.clone(),api.clone())),
 			validate_submission:crate::validate_submission::Validator::new(crate::validator::Validator::new(cookie_context,api)),
 		}
 	}
@@ -41,7 +47,9 @@ impl MessageHandler{
 		let message=message_result.map_err(HandleMessageError::Messages)?;
 		message.double_ack().await.map_err(HandleMessageError::DoubleAck)?;
 		match message.subject.as_str(){
+			"maptest.mapfixes.upload"=>self.upload_mapfix.upload(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadMapfix),
 			"maptest.submissions.upload"=>self.upload_submission.upload(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadSubmission),
+			"maptest.mapfixes.validate"=>self.validate_mapfix.validate(from_slice(&message.payload)?).await.map_err(HandleMessageError::ValidateMapfix),
 			"maptest.submissions.validate"=>self.validate_submission.validate(from_slice(&message.payload)?).await.map_err(HandleMessageError::ValidateSubmission),
 			other=>Err(HandleMessageError::UnknownSubject(other.to_owned()))
 		}
diff --git a/validation/src/nats_types.rs b/validation/src/nats_types.rs
index dc2369c..15f0924 100644
--- a/validation/src/nats_types.rs
+++ b/validation/src/nats_types.rs
@@ -33,3 +33,12 @@ pub struct UploadSubmissionRequest{
 	pub ModelVersion:u64,
 	pub ModelName:String,
 }
+
+#[allow(nonstandard_style)]
+#[derive(serde::Deserialize)]
+pub struct UploadMapfixRequest{
+	pub MapfixID:i64,
+	pub ModelID:u64,
+	pub ModelVersion:u64,
+	pub TargetAssetID:u64,
+}
diff --git a/validation/src/validator.rs b/validation/src/validator.rs
index 6babbf4..5d3b1ed 100644
--- a/validation/src/validator.rs
+++ b/validation/src/validator.rs
@@ -42,7 +42,7 @@ pub enum ValidateError{
 	ApiCreateScript(submissions_api::Error),
 	ApiCreateScriptPolicy(submissions_api::Error),
 	ApiGetScriptFromHash(submissions_api::types::SingleItemError),
-	ApiUpdateMapfixModelUnimplemented,
+	ApiUpdateMapfixModel(submissions_api::Error),
 	ApiUpdateSubmissionModel(submissions_api::Error),
 	ModelFileRootMustHaveOneChild,
 	ModelFileChildRefIsNil,
@@ -266,9 +266,13 @@ impl Validator{
 			};
 
 			match validate_info.ResourceID{
-				ResourceID::Mapfix(_mapfix_id)=>{
+				ResourceID::Mapfix(mapfix_id)=>{
 					// update the mapfix to use the validated model
-					return Err(ValidateError::ApiUpdateMapfixModelUnimplemented);
+					self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
+						MapfixID:mapfix_id,
+						ModelID:model_id,
+						ModelVersion:1, //TODO
+					}).await.map_err(ValidateError::ApiUpdateMapfixModel)?;
 				},
 				ResourceID::Submission(submission_id)=>{
 					// update the submission to use the validated model
-- 
2.47.1