From 42f0607d2acbab0cf3baef596b736104138f0547 Mon Sep 17 00:00:00 2001
From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com>
Date: Tue, 8 Sep 2026 09:21:51 +0000
Subject: [PATCH 1/2] feat!: remove has_ai_task and the task build reasons
Drop has_ai_task from template versions and workspace builds, and remove the task build reasons.
Map automatic task pauses to autostop and manual pauses or resumes to initiator in workspace builds and build orchestrations.
Replacing the build_reason enum rewrites workspace_builds; the timing test exercises 100,000 builds.
The down migration restores the schema but cannot recover original reasons or flag values, so restored flags are false.
---
coderd/database/dbauthz/dbauthz.go | 2 +-
coderd/database/dbauthz/dbauthz_test.go | 3 +-
coderd/database/dbfake/dbfake.go | 7 -
coderd/database/dbgen/dbgen.go | 8 +-
coderd/database/dump.sql | 11 +-
...as_ai_task_and_task_build_reasons.down.sql | 91 ++++++
..._has_ai_task_and_task_build_reasons.up.sql | 99 ++++++
coderd/database/migrations/migrate_test.go | 288 ++++++++++++++++++
coderd/database/modelqueries.go | 2 -
coderd/database/models.go | 15 +-
coderd/database/queries.sql.go | 146 +++------
coderd/database/queries/templates.sql | 6 -
coderd/database/queries/templateversions.sql | 5 +-
coderd/database/queries/workspacebuilds.sql | 1 -
coderd/database/queries/workspaces.sql | 16 -
.../provisionerdserver/provisionerdserver.go | 6 -
docs/admin/security/audit-logs.md | 4 +-
enterprise/audit/table.go | 2 -
18 files changed, 533 insertions(+), 179 deletions(-)
create mode 100644 coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql
create mode 100644 coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql
diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go
index 14f7f33c7e4e6..4b281f074c8b6 100644
--- a/coderd/database/dbauthz/dbauthz.go
+++ b/coderd/database/dbauthz/dbauthz.go
@@ -8335,7 +8335,7 @@ func (q *querier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.
}
func (q *querier) UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg database.UpdateTemplateVersionFlagsByJobIDParams) error {
- // An actor is allowed to update the template version ai task and external agent flag if they are authorized to update the template.
+ // An actor is allowed to update the template version external agent flag if they are authorized to update the template.
tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID)
if err != nil {
return err
diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index 3cd7b3a3faa9e..9f87cfec00850 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -2906,7 +2906,7 @@ func (s *MethodTestSuite) TestTemplate() {
s.Run("UpdateTemplateVersionFlagsByJobID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
t := testutil.Fake(s.T(), faker, database.Template{})
tv := testutil.Fake(s.T(), faker, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}})
- arg := database.UpdateTemplateVersionFlagsByJobIDParams{JobID: tv.JobID, HasAITask: sql.NullBool{Bool: true, Valid: true}, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}}
+ arg := database.UpdateTemplateVersionFlagsByJobIDParams{JobID: tv.JobID, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}}
dbm.EXPECT().GetTemplateVersionByJobID(gomock.Any(), tv.JobID).Return(tv, nil).AnyTimes()
dbm.EXPECT().GetTemplateByID(gomock.Any(), t.ID).Return(t, nil).AnyTimes()
dbm.EXPECT().UpdateTemplateVersionFlagsByJobID(gomock.Any(), arg).Return(nil).AnyTimes()
@@ -4453,7 +4453,6 @@ func (s *MethodTestSuite) TestWorkspace() {
dbm.EXPECT().UpdateWorkspaceBuildFlagsByID(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
check.Args(database.UpdateWorkspaceBuildFlagsByIDParams{
ID: b.ID,
- HasAITask: sql.NullBool{Bool: true, Valid: true},
HasExternalAgent: sql.NullBool{Bool: true, Valid: true},
UpdatedAt: b.UpdatedAt,
}).Asserts(w, policy.ActionUpdate)
diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go
index d2d0834df662c..1bcd25408a35a 100644
--- a/coderd/database/dbfake/dbfake.go
+++ b/coderd/database/dbfake/dbfake.go
@@ -297,13 +297,6 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
b.seed.ID = uuid.New()
b.seed.JobID = jobID
- if b.taskAppID != uuid.Nil {
- b.seed.HasAITask = sql.NullBool{
- Bool: true,
- Valid: true,
- }
- }
-
resp := WorkspaceResponse{
AgentToken: b.agentToken,
Agents: make([]database.WorkspaceAgent, 0),
diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go
index ad67930ddfec0..b6a8f82867ce5 100644
--- a/coderd/database/dbgen/dbgen.go
+++ b/coderd/database/dbgen/dbgen.go
@@ -936,7 +936,6 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil
buildID := takeFirst(orig.ID, uuid.New())
jobID := takeFirst(orig.JobID, uuid.New())
- hasAITask := takeFirst(orig.HasAITask, sql.NullBool{})
hasExternalAgent := takeFirst(orig.HasExternalAgent, sql.NullBool{})
var build database.WorkspaceBuild
err := db.InTx(func(db database.Store) error {
@@ -971,10 +970,9 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil
require.NoError(t, err)
}
- if hasAITask.Valid || hasExternalAgent.Valid {
+ if hasExternalAgent.Valid {
require.NoError(t, db.UpdateWorkspaceBuildFlagsByID(genCtx, database.UpdateWorkspaceBuildFlagsByIDParams{
ID: buildID,
- HasAITask: hasAITask,
HasExternalAgent: hasExternalAgent,
UpdatedAt: dbtime.Now(),
}))
@@ -1592,7 +1590,6 @@ func ExternalAuthLink(t testing.TB, db database.Store, orig database.ExternalAut
func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVersion) database.TemplateVersion {
var version database.TemplateVersion
- hasAITask := takeFirst(orig.HasAITask, sql.NullBool{})
hasExternalAgent := takeFirst(orig.HasExternalAgent, sql.NullBool{})
jobID := takeFirst(orig.JobID, uuid.New())
err := db.InTx(func(db database.Store) error {
@@ -1614,10 +1611,9 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers
return err
}
- if hasAITask.Valid || hasExternalAgent.Valid {
+ if hasExternalAgent.Valid {
require.NoError(t, db.UpdateTemplateVersionFlagsByJobID(genCtx, database.UpdateTemplateVersionFlagsByJobIDParams{
JobID: jobID,
- HasAITask: hasAITask,
HasExternalAgent: hasExternalAgent,
UpdatedAt: dbtime.Now(),
}))
diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql
index abbfda38e5c9b..d33a18ef14b3f 100644
--- a/coderd/database/dump.sql
+++ b/coderd/database/dump.sql
@@ -334,10 +334,7 @@ CREATE TYPE build_reason AS ENUM (
'cli',
'ssh_connection',
'vscode_connection',
- 'jetbrains_connection',
- 'task_auto_pause',
- 'task_manual_pause',
- 'task_resume'
+ 'jetbrains_connection'
);
CREATE TYPE chat_client_type AS ENUM (
@@ -3189,7 +3186,6 @@ CREATE TABLE workspace_builds (
daily_cost integer DEFAULT 0 NOT NULL,
max_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL,
template_version_preset_id uuid,
- has_ai_task boolean,
has_external_agent boolean,
notified_autostop_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL,
CONSTRAINT workspace_builds_deadline_below_max_deadline CHECK ((((deadline <> '0001-01-01 00:00:00+00'::timestamp with time zone) AND (deadline <= max_deadline)) OR (max_deadline = '0001-01-01 00:00:00+00'::timestamp with time zone)))
@@ -3500,7 +3496,6 @@ CREATE TABLE template_versions (
message character varying(1048576) DEFAULT ''::character varying NOT NULL,
archived boolean DEFAULT false NOT NULL,
source_example_id text,
- has_ai_task boolean,
has_external_agent boolean
);
@@ -3522,7 +3517,6 @@ CREATE VIEW template_version_with_user AS
template_versions.message,
template_versions.archived,
template_versions.source_example_id,
- template_versions.has_ai_task,
template_versions.has_external_agent,
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
COALESCE(visible_users.username, ''::text) AS created_by_username,
@@ -4132,7 +4126,6 @@ CREATE VIEW workspace_build_with_user AS
workspace_builds.daily_cost,
workspace_builds.max_deadline,
workspace_builds.template_version_preset_id,
- workspace_builds.has_ai_task,
workspace_builds.has_external_agent,
workspace_builds.notified_autostop_deadline,
COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url,
@@ -5019,8 +5012,6 @@ CREATE INDEX idx_telemetry_locks_period_ending_at ON telemetry_locks USING btree
CREATE UNIQUE INDEX idx_template_version_presets_default ON template_version_presets USING btree (template_version_id) WHERE (is_default = true);
-CREATE INDEX idx_template_versions_has_ai_task ON template_versions USING btree (has_ai_task);
-
CREATE UNIQUE INDEX idx_unique_preset_name ON template_version_presets USING btree (name, template_version_id);
CREATE UNIQUE INDEX idx_usage_events_agent_runtime ON usage_events USING btree (event_type, created_at) WHERE (event_type = 'hb_agent_runtime_v1'::text);
diff --git a/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql b/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql
new file mode 100644
index 0000000000000..d633f79969934
--- /dev/null
+++ b/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql
@@ -0,0 +1,91 @@
+-- Drop views before modifying underlying tables and columns.
+DROP VIEW IF EXISTS template_version_with_user;
+DROP VIEW IF EXISTS workspace_build_with_user;
+
+-- Recreate has_ai_task columns and index. The dropped values are not
+-- recoverable, so backfill false to satisfy older migrations that restore
+-- NOT NULL on the way further down.
+ALTER TABLE template_versions ADD COLUMN has_ai_task boolean DEFAULT false;
+ALTER TABLE template_versions ALTER COLUMN has_ai_task DROP DEFAULT;
+CREATE INDEX idx_template_versions_has_ai_task ON template_versions USING btree (has_ai_task);
+ALTER TABLE workspace_builds ADD COLUMN has_ai_task boolean DEFAULT false;
+ALTER TABLE workspace_builds ALTER COLUMN has_ai_task DROP DEFAULT;
+
+-- Recreate build_reason enum with task values.
+ALTER TYPE build_reason RENAME TO build_reason_old;
+
+CREATE TYPE build_reason AS ENUM (
+ 'initiator',
+ 'autostart',
+ 'autostop',
+ 'dormancy',
+ 'failedstop',
+ 'autodelete',
+ 'dashboard',
+ 'cli',
+ 'ssh_connection',
+ 'vscode_connection',
+ 'jetbrains_connection',
+ 'task_auto_pause',
+ 'task_manual_pause',
+ 'task_resume'
+);
+
+ALTER TABLE workspace_builds ALTER COLUMN reason DROP DEFAULT;
+ALTER TABLE workspace_builds ALTER COLUMN reason TYPE build_reason USING (reason::text::build_reason);
+ALTER TABLE workspace_builds ALTER COLUMN reason SET DEFAULT 'initiator'::build_reason;
+
+ALTER TABLE workspace_build_orchestrations ALTER COLUMN child_reason TYPE build_reason USING (child_reason::text::build_reason);
+
+DROP TYPE build_reason_old;
+
+-- Recreate views.
+CREATE VIEW template_version_with_user AS
+ SELECT template_versions.id,
+ template_versions.template_id,
+ template_versions.organization_id,
+ template_versions.created_at,
+ template_versions.updated_at,
+ template_versions.name,
+ template_versions.readme,
+ template_versions.job_id,
+ template_versions.created_by,
+ template_versions.external_auth_providers,
+ template_versions.message,
+ template_versions.archived,
+ template_versions.source_example_id,
+ template_versions.has_ai_task,
+ template_versions.has_external_agent,
+ COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
+ COALESCE(visible_users.username, ''::text) AS created_by_username,
+ COALESCE(visible_users.name, ''::text) AS created_by_name
+ FROM (template_versions
+ LEFT JOIN visible_users ON ((template_versions.created_by = visible_users.id)));
+
+COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
+
+CREATE VIEW workspace_build_with_user AS
+ SELECT workspace_builds.id,
+ workspace_builds.created_at,
+ workspace_builds.updated_at,
+ workspace_builds.workspace_id,
+ workspace_builds.template_version_id,
+ workspace_builds.build_number,
+ workspace_builds.transition,
+ workspace_builds.initiator_id,
+ workspace_builds.job_id,
+ workspace_builds.deadline,
+ workspace_builds.reason,
+ workspace_builds.daily_cost,
+ workspace_builds.max_deadline,
+ workspace_builds.template_version_preset_id,
+ workspace_builds.has_ai_task,
+ workspace_builds.has_external_agent,
+ workspace_builds.notified_autostop_deadline,
+ COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url,
+ COALESCE(visible_users.username, ''::text) AS initiator_by_username,
+ COALESCE(visible_users.name, ''::text) AS initiator_by_name
+ FROM (workspace_builds
+ LEFT JOIN visible_users ON ((workspace_builds.initiator_id = visible_users.id)));
+
+COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.';
diff --git a/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql b/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql
new file mode 100644
index 0000000000000..9de1cdfe69510
--- /dev/null
+++ b/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql
@@ -0,0 +1,99 @@
+DROP VIEW IF EXISTS template_version_with_user;
+DROP VIEW IF EXISTS workspace_build_with_user;
+
+-- Drop has_ai_task index and columns.
+DROP INDEX IF EXISTS idx_template_versions_has_ai_task;
+ALTER TABLE template_versions DROP COLUMN IF EXISTS has_ai_task;
+ALTER TABLE workspace_builds DROP COLUMN IF EXISTS has_ai_task;
+
+-- Remove task-related build reasons from build_reason enum. Automatic
+-- pauses stay system-attributed; manual pauses and resumes were created by
+-- authenticated user requests, so they keep user attribution as initiator.
+UPDATE workspace_builds
+SET reason = 'autostop'
+WHERE reason::text = 'task_auto_pause';
+
+UPDATE workspace_builds
+SET reason = 'initiator'
+WHERE reason::text IN ('task_manual_pause', 'task_resume');
+
+UPDATE workspace_build_orchestrations
+SET child_reason = 'autostop'
+WHERE child_reason::text = 'task_auto_pause';
+
+UPDATE workspace_build_orchestrations
+SET child_reason = 'initiator'
+WHERE child_reason::text IN ('task_manual_pause', 'task_resume');
+
+ALTER TYPE build_reason RENAME TO build_reason_old;
+
+CREATE TYPE build_reason AS ENUM (
+ 'initiator',
+ 'autostart',
+ 'autostop',
+ 'dormancy',
+ 'failedstop',
+ 'autodelete',
+ 'dashboard',
+ 'cli',
+ 'ssh_connection',
+ 'vscode_connection',
+ 'jetbrains_connection'
+);
+
+ALTER TABLE workspace_builds ALTER COLUMN reason DROP DEFAULT;
+ALTER TABLE workspace_builds ALTER COLUMN reason TYPE build_reason USING (reason::text::build_reason);
+ALTER TABLE workspace_builds ALTER COLUMN reason SET DEFAULT 'initiator'::build_reason;
+
+ALTER TABLE workspace_build_orchestrations ALTER COLUMN child_reason TYPE build_reason USING (child_reason::text::build_reason);
+
+DROP TYPE build_reason_old;
+
+-- Recreate views without task columns.
+CREATE VIEW template_version_with_user AS
+ SELECT template_versions.id,
+ template_versions.template_id,
+ template_versions.organization_id,
+ template_versions.created_at,
+ template_versions.updated_at,
+ template_versions.name,
+ template_versions.readme,
+ template_versions.job_id,
+ template_versions.created_by,
+ template_versions.external_auth_providers,
+ template_versions.message,
+ template_versions.archived,
+ template_versions.source_example_id,
+ template_versions.has_external_agent,
+ COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
+ COALESCE(visible_users.username, ''::text) AS created_by_username,
+ COALESCE(visible_users.name, ''::text) AS created_by_name
+ FROM (template_versions
+ LEFT JOIN visible_users ON ((template_versions.created_by = visible_users.id)));
+
+COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
+
+CREATE VIEW workspace_build_with_user AS
+ SELECT workspace_builds.id,
+ workspace_builds.created_at,
+ workspace_builds.updated_at,
+ workspace_builds.workspace_id,
+ workspace_builds.template_version_id,
+ workspace_builds.build_number,
+ workspace_builds.transition,
+ workspace_builds.initiator_id,
+ workspace_builds.job_id,
+ workspace_builds.deadline,
+ workspace_builds.reason,
+ workspace_builds.daily_cost,
+ workspace_builds.max_deadline,
+ workspace_builds.template_version_preset_id,
+ workspace_builds.has_external_agent,
+ workspace_builds.notified_autostop_deadline,
+ COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url,
+ COALESCE(visible_users.username, ''::text) AS initiator_by_username,
+ COALESCE(visible_users.name, ''::text) AS initiator_by_name
+ FROM (workspace_builds
+ LEFT JOIN visible_users ON ((workspace_builds.initiator_id = visible_users.id)));
+
+COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.';
diff --git a/coderd/database/migrations/migrate_test.go b/coderd/database/migrations/migrate_test.go
index 9844d8ec4bdbc..27af55f0799a8 100644
--- a/coderd/database/migrations/migrate_test.go
+++ b/coderd/database/migrations/migrate_test.go
@@ -1190,6 +1190,294 @@ func TestMigration000475AgentsAccessOrgRole(t *testing.T) {
)
}
+func TestMigration000592RemoveHasAITaskAndTaskBuildReasons(t *testing.T) {
+ t.Parallel()
+
+ const migrationVersion = 592
+ sqlDB := testSQLDB(t)
+ next, err := migrations.Stepper(sqlDB)
+ require.NoError(t, err)
+ for {
+ version, more, err := next()
+ require.NoError(t, err)
+ if !more {
+ t.Fatalf("migration %d not found", migrationVersion)
+ }
+ if version == migrationVersion-1 {
+ break
+ }
+ }
+
+ ctx := testutil.Context(t, testutil.WaitLong)
+ now := time.Now().UTC().Truncate(time.Microsecond)
+ orgID, userID, templateID, versionID, templateJobID, workspaceID := uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New()
+ buildIDs := []uuid.UUID{uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New()}
+ fixtures := []struct {
+ query string
+ args []any
+ }{
+ {
+ "INSERT INTO organizations (id, name, display_name, description, created_at, updated_at, default_org_member_roles) VALUES ($1, $2, '', '', $3, $3, '{}')",
+ []any{orgID, orgID.String(), now},
+ },
+ {
+ "INSERT INTO users (id, username, email, hashed_password, created_at, updated_at) VALUES ($1, $2, $3, '', $4, $4)",
+ []any{userID, userID.String(), userID.String() + "@test.com", now},
+ },
+ {
+ "INSERT INTO provisioner_jobs (id, created_at, updated_at, organization_id, initiator_id, provisioner, storage_method, file_id, type, input) VALUES ($1, $2, $2, $3, $4, 'echo', 'file', $1, 'template_version_import', '{}')",
+ []any{templateJobID, now, orgID, userID},
+ },
+ {
+ "INSERT INTO template_versions (id, organization_id, name, readme, created_at, updated_at, job_id, created_by, has_ai_task) VALUES ($1, $2, 'v1', '', $3, $3, $4, $5, true)",
+ []any{versionID, orgID, now, templateJobID, userID},
+ },
+ {
+ "INSERT INTO templates (id, organization_id, name, created_at, updated_at, provisioner, active_version_id, created_by) VALUES ($1, $2, 'build-reasons', $3, $3, 'echo', $4, $5)",
+ []any{templateID, orgID, now, versionID, userID},
+ },
+ {
+ "UPDATE template_versions SET template_id = $1 WHERE id = $2",
+ []any{templateID, versionID},
+ },
+ {
+ "INSERT INTO workspaces (id, created_at, updated_at, owner_id, organization_id, template_id, name) VALUES ($1, $2, $2, $3, $4, $5, 'build-reasons')",
+ []any{workspaceID, now, userID, orgID, templateID},
+ },
+ }
+ for _, fixture := range fixtures {
+ _, err := sqlDB.ExecContext(ctx, fixture.query, fixture.args...)
+ require.NoError(t, err)
+ }
+ for i, reason := range []string{"task_auto_pause", "task_manual_pause", "task_resume", "initiator", "autostop"} {
+ jobID := uuid.New()
+ _, err = sqlDB.ExecContext(ctx,
+ "INSERT INTO provisioner_jobs (id, created_at, updated_at, organization_id, initiator_id, provisioner, storage_method, file_id, type, input) VALUES ($1, $2, $2, $3, $4, 'echo', 'file', $1, 'workspace_build', '{}')",
+ jobID, now, orgID, userID)
+ require.NoError(t, err)
+ _, err = sqlDB.ExecContext(ctx,
+ "INSERT INTO workspace_builds (id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, reason, has_ai_task) VALUES ($1, $2, $2, $3, $4, $5, 'start', $6, $7, $8, $9)",
+ buildIDs[i], now, workspaceID, versionID, i+1, userID, jobID, reason, i == 0)
+ require.NoError(t, err)
+ }
+ _, err = sqlDB.ExecContext(ctx,
+ "INSERT INTO workspace_build_orchestrations (id, created_at, updated_at, workspace_id, parent_build_id, child_transition, child_reason) VALUES ($1, $2, $2, $3, $4, 'start', 'task_auto_pause')",
+ uuid.New(), now, workspaceID, buildIDs[0])
+ require.NoError(t, err)
+
+ version, _, err := next()
+ require.NoError(t, err)
+ require.EqualValues(t, migrationVersion, version)
+ var count int
+ const columnsQuery = "SELECT count(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name IN ('template_versions', 'workspace_builds') AND column_name = 'has_ai_task'"
+ require.NoError(t, sqlDB.QueryRowContext(ctx, columnsQuery).Scan(&count))
+ require.Zero(t, count)
+ const indexQuery = "SELECT count(*) FROM pg_indexes WHERE schemaname = 'public' AND indexname = 'idx_template_versions_has_ai_task'"
+ require.NoError(t, sqlDB.QueryRowContext(ctx, indexQuery).Scan(&count))
+ require.Zero(t, count)
+ var reasons pq.StringArray
+ const reasonsQuery = "SELECT array_agg(reason::text ORDER BY build_number) FROM workspace_builds WHERE workspace_id = $1"
+ wantReasons := pq.StringArray{"autostop", "initiator", "initiator", "initiator", "autostop"}
+ require.NoError(t, sqlDB.QueryRowContext(ctx, reasonsQuery, workspaceID).Scan(&reasons))
+ require.Equal(t, wantReasons, reasons)
+ var childReason string
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason))
+ require.Equal(t, "autostop", childReason)
+ var enumValues pq.StringArray
+ const enumQuery = "SELECT enum_range(NULL::build_reason)::text[]"
+ require.NoError(t, sqlDB.QueryRowContext(ctx, enumQuery).Scan(&enumValues))
+ wantEnum := pq.StringArray{"initiator", "autostart", "autostop", "dormancy", "failedstop", "autodelete", "dashboard", "cli", "ssh_connection", "vscode_connection", "jetbrains_connection"}
+ require.Equal(t, wantEnum, enumValues)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_version_with_user").Scan(&count))
+ require.Equal(t, 1, count)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_build_with_user").Scan(&count))
+ require.Equal(t, len(buildIDs), count)
+
+ downSQL, err := os.ReadFile("000592_remove_has_ai_task_and_task_build_reasons.down.sql")
+ require.NoError(t, err)
+ _, err = sqlDB.ExecContext(ctx, string(downSQL))
+ require.NoError(t, err)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, columnsQuery).Scan(&count))
+ require.Equal(t, 2, count)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, indexQuery).Scan(&count))
+ require.Equal(t, 1, count)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_versions WHERE has_ai_task IS FALSE").Scan(&count))
+ require.Equal(t, 1, count)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_builds WHERE has_ai_task IS FALSE").Scan(&count))
+ require.Equal(t, len(buildIDs), count)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, enumQuery).Scan(&enumValues))
+ require.Equal(t, append(wantEnum, "task_auto_pause", "task_manual_pause", "task_resume"), enumValues)
+ // The original reasons cannot be recovered after remapping.
+ require.NoError(t, sqlDB.QueryRowContext(ctx, reasonsQuery, workspaceID).Scan(&reasons))
+ require.Equal(t, wantReasons, reasons)
+ require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason))
+ require.Equal(t, "autostop", childReason)
+
+ upSQL, err := os.ReadFile("000592_remove_has_ai_task_and_task_build_reasons.up.sql")
+ require.NoError(t, err)
+ _, err = sqlDB.ExecContext(ctx, string(upSQL))
+ require.NoError(t, err)
+}
+
+func TestMigration000592TaskBuildReasonRewriteTiming(t *testing.T) {
+ t.Parallel()
+
+ if testing.Short() {
+ t.SkipNow()
+ return
+ }
+
+ // The enum replacement rewrites workspace_builds, risking slow upgrades
+ // on large deployments.
+ const (
+ migrationVersion = 592
+ workspaceCount = 1_000
+ buildCount = 100_000
+ buildsPerWorkspace = buildCount / workspaceCount
+ orchestrationCount = 5_000
+ taskReasonBuilds = 3 * buildCount / 10
+ )
+
+ sqlDB := testSQLDB(t)
+ next, err := migrations.Stepper(sqlDB)
+ require.NoError(t, err)
+ for {
+ version, more, err := next()
+ require.NoError(t, err)
+ if !more {
+ t.Fatalf("migration %d not found", migrationVersion)
+ }
+ if version == migrationVersion-1 {
+ break
+ }
+ }
+
+ ctx := testutil.Context(t, testutil.WaitSuperLong)
+ now := time.Now().UTC().Truncate(time.Microsecond)
+
+ orgID := uuid.New()
+ userID := uuid.New()
+ templateID := uuid.New()
+ templateVersionID := uuid.New()
+ templateJobID := uuid.New()
+
+ // Deterministic IDs let the bulk inserts join rows generated by
+ // generate_series without round-tripping IDs through the test.
+ const (
+ workspaceIDPattern = "('a0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid"
+ jobIDPattern = "('b0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid"
+ buildIDPattern = "('c0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid"
+ )
+
+ fixtures := []struct {
+ query string
+ args []any
+ }{
+ {
+ `INSERT INTO organizations (id, name, display_name, description, created_at, updated_at, default_org_member_roles) VALUES ($1, $2, $3, $4, $5, $6, '{}')`,
+ []any{orgID, "timing-org", "Timing Org", "", now, now},
+ },
+ {
+ `INSERT INTO users (id, username, email, hashed_password, created_at, updated_at, status, rbac_roles, login_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
+ []any{userID, "timinguser", "timing@example.com", []byte{}, now, now, "active", []byte("{}"), "password"},
+ },
+ {
+ `INSERT INTO provisioner_jobs (id, created_at, updated_at, started_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, file_id, type, input, tags) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`,
+ []any{templateJobID, now, now, now, now, "", orgID, userID, "terraform", "file", uuid.New(), "template_version_import", []byte("{}"), []byte("{}")},
+ },
+ {
+ `INSERT INTO template_versions (id, organization_id, name, readme, created_at, updated_at, job_id, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
+ []any{templateVersionID, orgID, "v1.0", "", now, now, templateJobID, userID},
+ },
+ {
+ `INSERT INTO templates (id, organization_id, name, created_at, updated_at, provisioner, active_version_id, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
+ []any{templateID, orgID, "timing-template", now, now, "terraform", templateVersionID, userID},
+ },
+ {
+ `UPDATE template_versions SET template_id = $1 WHERE id = $2`,
+ []any{templateID, templateVersionID},
+ },
+ {
+ fmt.Sprintf(`INSERT INTO workspaces (id, created_at, updated_at, owner_id, organization_id, template_id, name, last_used_at)
+ SELECT `+workspaceIDPattern+`, $1, $1, $2, $3, $4, 'timing-ws-' || g, $1
+ FROM generate_series(0, %d) AS g`, "g", workspaceCount-1),
+ []any{now, userID, orgID, templateID},
+ },
+ {
+ fmt.Sprintf(`INSERT INTO provisioner_jobs (id, created_at, updated_at, started_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, file_id, type, input, tags)
+ SELECT `+jobIDPattern+`, $1, $1, $1, $1, '', $2, $3, 'terraform', 'file', $4, 'workspace_build', '{}'::jsonb, '{}'::jsonb
+ FROM generate_series(0, %d) AS g`, "g", buildCount-1),
+ []any{now, orgID, userID, uuid.New()},
+ },
+ {
+ fmt.Sprintf(`INSERT INTO workspace_builds (id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, reason, has_ai_task)
+ SELECT `+buildIDPattern+`, $1, $1, `+fmt.Sprintf(workspaceIDPattern, "(g / %d)")+`, $2, (g %% %d) + 1,
+ CASE WHEN g %% 2 = 0 THEN 'start' ELSE 'stop' END::workspace_transition, $3, `+jobIDPattern+`,
+ CASE g %% 10
+ WHEN 0 THEN 'task_auto_pause'
+ WHEN 1 THEN 'task_manual_pause'
+ WHEN 2 THEN 'task_resume'
+ WHEN 3 THEN 'autostart'
+ WHEN 4 THEN 'autostop'
+ ELSE 'initiator'
+ END::build_reason,
+ CASE WHEN g %% 10 < 3 THEN true END
+ FROM generate_series(0, %d) AS g`, "g", buildsPerWorkspace, buildsPerWorkspace, "g", buildCount-1),
+ []any{now, templateVersionID, userID},
+ },
+ {
+ fmt.Sprintf(`INSERT INTO workspace_build_orchestrations (id, created_at, updated_at, workspace_id, parent_build_id, child_transition, child_reason)
+ SELECT ('e0000000-0000-4000-8000-' || lpad(g::text, 12, '0'))::uuid, $1, $1, `+fmt.Sprintf(workspaceIDPattern, "(g * 20 / %d)")+`, `+fmt.Sprintf(buildIDPattern, "(g * 20)")+`, 'start',
+ CASE g %% 3
+ WHEN 0 THEN 'task_auto_pause'
+ WHEN 1 THEN 'task_resume'
+ ELSE 'initiator'
+ END::build_reason
+ FROM generate_series(0, %d) AS g`, buildsPerWorkspace, orchestrationCount-1),
+ []any{now},
+ },
+ }
+ for i, fixture := range fixtures {
+ _, err := sqlDB.ExecContext(ctx, fixture.query, fixture.args...)
+ require.NoErrorf(t, err, "fixture %d", i)
+ }
+
+ countByReason := func(table, column, reason string) int {
+ var n int
+ //nolint:gosec // Test-only query built from constant table/column names.
+ err := sqlDB.QueryRowContext(ctx, fmt.Sprintf("SELECT count(*) FROM %s WHERE %s::text = $1", table, column), reason).Scan(&n)
+ require.NoError(t, err)
+ return n
+ }
+ wantAutostop := countByReason("workspace_builds", "reason", "autostop") + countByReason("workspace_builds", "reason", "task_auto_pause")
+ wantInitiator := countByReason("workspace_builds", "reason", "initiator") + countByReason("workspace_builds", "reason", "task_manual_pause") + countByReason("workspace_builds", "reason", "task_resume")
+ wantChildAutostop := countByReason("workspace_build_orchestrations", "child_reason", "autostop") + countByReason("workspace_build_orchestrations", "child_reason", "task_auto_pause")
+ wantChildInitiator := countByReason("workspace_build_orchestrations", "child_reason", "initiator") + countByReason("workspace_build_orchestrations", "child_reason", "task_resume")
+
+ start := time.Now()
+ version, _, err := next()
+ require.NoError(t, err)
+ require.EqualValues(t, migrationVersion, version)
+ elapsed := time.Since(start)
+ t.Logf("migration %d over %d workspace builds (%d with task reasons) and %d orchestrations took %s", migrationVersion, buildCount, taskReasonBuilds, orchestrationCount, elapsed)
+ // Bound migration time to catch regressions that could prolong upgrade downtime.
+ require.Lessf(t, elapsed, 2*time.Minute, "migration %d took %s at %d workspace builds", migrationVersion, elapsed, buildCount)
+
+ var totalBuilds int
+ err = sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_builds").Scan(&totalBuilds)
+ require.NoError(t, err)
+ require.Equal(t, buildCount, totalBuilds)
+ require.Equal(t, wantAutostop, countByReason("workspace_builds", "reason", "autostop"))
+ require.Equal(t, wantInitiator, countByReason("workspace_builds", "reason", "initiator"))
+ require.Equal(t, wantChildAutostop, countByReason("workspace_build_orchestrations", "child_reason", "autostop"))
+ require.Equal(t, wantChildInitiator, countByReason("workspace_build_orchestrations", "child_reason", "initiator"))
+
+ var count int
+ err = sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'workspace_builds' AND column_name = 'has_ai_task'").Scan(&count)
+ require.NoError(t, err)
+ require.Zero(t, count)
+}
+
func TestMigration000587RemoveAgentsAccessRole(t *testing.T) {
t.Parallel()
diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go
index 8345b8bd5a4b3..b0d06b65d5d72 100644
--- a/coderd/database/modelqueries.go
+++ b/coderd/database/modelqueries.go
@@ -145,7 +145,6 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
arg.FuzzyDisplayName,
pq.Array(arg.IDs),
arg.Deprecated,
- arg.HasAITask,
arg.AgentsAllowed,
arg.AuthorID,
arg.AuthorUsername,
@@ -340,7 +339,6 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa
arg.LastUsedBefore,
arg.LastUsedAfter,
arg.UsingActive,
- arg.HasAITask,
arg.HasExternalAgent,
arg.Shared,
arg.SharedWithUserID,
diff --git a/coderd/database/models.go b/coderd/database/models.go
index b5a1340b353c4..d60a493c22c61 100644
--- a/coderd/database/models.go
+++ b/coderd/database/models.go
@@ -1366,9 +1366,6 @@ const (
BuildReasonSshConnection BuildReason = "ssh_connection"
BuildReasonVscodeConnection BuildReason = "vscode_connection"
BuildReasonJetbrainsConnection BuildReason = "jetbrains_connection"
- BuildReasonTaskAutoPause BuildReason = "task_auto_pause"
- BuildReasonTaskManualPause BuildReason = "task_manual_pause"
- BuildReasonTaskResume BuildReason = "task_resume"
)
func (e *BuildReason) Scan(src interface{}) error {
@@ -1418,10 +1415,7 @@ func (e BuildReason) Valid() bool {
BuildReasonCli,
BuildReasonSshConnection,
BuildReasonVscodeConnection,
- BuildReasonJetbrainsConnection,
- BuildReasonTaskAutoPause,
- BuildReasonTaskManualPause,
- BuildReasonTaskResume:
+ BuildReasonJetbrainsConnection:
return true
}
return false
@@ -1440,9 +1434,6 @@ func AllBuildReasonValues() []BuildReason {
BuildReasonSshConnection,
BuildReasonVscodeConnection,
BuildReasonJetbrainsConnection,
- BuildReasonTaskAutoPause,
- BuildReasonTaskManualPause,
- BuildReasonTaskResume,
}
}
@@ -6214,7 +6205,6 @@ type TemplateVersion struct {
Message string `db:"message" json:"message"`
Archived bool `db:"archived" json:"archived"`
SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
@@ -6306,7 +6296,6 @@ type TemplateVersionTable struct {
Message string `db:"message" json:"message"`
Archived bool `db:"archived" json:"archived"`
SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
}
@@ -6840,7 +6829,6 @@ type WorkspaceBuild struct {
DailyCost int32 `db:"daily_cost" json:"daily_cost"`
MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"`
TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
NotifiedAutostopDeadline time.Time `db:"notified_autostop_deadline" json:"notified_autostop_deadline"`
InitiatorByAvatarUrl string `db:"initiator_by_avatar_url" json:"initiator_by_avatar_url"`
@@ -6897,7 +6885,6 @@ type WorkspaceBuildTable struct {
DailyCost int32 `db:"daily_cost" json:"daily_cost"`
MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"`
TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
// The autostop deadline value that an autostop reminder notification was last sent for. Used for idempotence: when it equals the build deadline the reminder has already been sent, and it re-arms automatically when the deadline changes.
NotifiedAutostopDeadline time.Time `db:"notified_autostop_deadline" json:"notified_autostop_deadline"`
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 26d2a934c618f..fe06b407691ee 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -28275,35 +28275,29 @@ WHERE
END
ELSE true
END
- -- Filter by has_ai_task in latest version
- AND CASE
- WHEN $9 :: boolean IS NOT NULL THEN
- tv.has_ai_task = $9 :: boolean
- ELSE true
- END
-- Filter by agents_allowed
AND CASE
- WHEN $10 :: boolean IS NOT NULL THEN
- t.agents_allowed = $10 :: boolean
+ WHEN $9 :: boolean IS NOT NULL THEN
+ t.agents_allowed = $9 :: boolean
ELSE true
END
-- Filter by author_id
AND CASE
- WHEN $11 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
- t.created_by = $11
+ WHEN $10 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
+ t.created_by = $10
ELSE true
END
-- Filter by author_username
AND CASE
- WHEN $12 :: text != '' THEN
- t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower($12) AND deleted = false)
+ WHEN $11 :: text != '' THEN
+ t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower($11) AND deleted = false)
ELSE true
END
-- Filter by has_external_agent in latest version
AND CASE
- WHEN $13 :: boolean IS NOT NULL THEN
- tv.has_external_agent = $13 :: boolean
+ WHEN $12 :: boolean IS NOT NULL THEN
+ tv.has_external_agent = $12 :: boolean
ELSE true
END
-- Authorize Filter clause will be injected below in GetAuthorizedTemplates
@@ -28320,7 +28314,6 @@ type GetTemplatesWithFilterParams struct {
FuzzyDisplayName string `db:"fuzzy_display_name" json:"fuzzy_display_name"`
IDs []uuid.UUID `db:"ids" json:"ids"`
Deprecated sql.NullBool `db:"deprecated" json:"deprecated"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
AgentsAllowed sql.NullBool `db:"agents_allowed" json:"agents_allowed"`
AuthorID uuid.UUID `db:"author_id" json:"author_id"`
AuthorUsername string `db:"author_username" json:"author_username"`
@@ -28337,7 +28330,6 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
arg.FuzzyDisplayName,
pq.Array(arg.IDs),
arg.Deprecated,
- arg.HasAITask,
arg.AgentsAllowed,
arg.AuthorID,
arg.AuthorUsername,
@@ -28848,7 +28840,7 @@ FROM
-- Scope an archive to a single template and ignore already archived template versions
(
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent
FROM
template_versions
WHERE
@@ -28949,7 +28941,7 @@ func (q *sqlQuerier) ArchiveUnusedTemplateVersions(ctx context.Context, arg Arch
const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -28987,7 +28979,6 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -28998,7 +28989,7 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev
const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -29022,7 +29013,6 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29033,7 +29023,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) (
const getTemplateVersionByJobID = `-- name: GetTemplateVersionByJobID :one
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -29057,7 +29047,6 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29068,7 +29057,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U
const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -29098,7 +29087,6 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29109,7 +29097,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context,
const getTemplateVersionsByIDs = `-- name: GetTemplateVersionsByIDs :many
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -29139,7 +29127,6 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29160,7 +29147,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU
const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many
SELECT
- id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
+ id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name
FROM
template_version_with_user AS template_versions
WHERE
@@ -29237,7 +29224,6 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29257,7 +29243,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge
}
const getTemplateVersionsCreatedAfter = `-- name: GetTemplateVersionsCreatedAfter :many
-SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE created_at > $1
+SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE created_at > $1
`
func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error) {
@@ -29283,7 +29269,6 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create
&i.Message,
&i.Archived,
&i.SourceExampleID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
@@ -29450,27 +29435,20 @@ const updateTemplateVersionFlagsByJobID = `-- name: UpdateTemplateVersionFlagsBy
UPDATE
template_versions
SET
- has_ai_task = $2,
- has_external_agent = $3,
- updated_at = $4
+ has_external_agent = $2,
+ updated_at = $3
WHERE
job_id = $1
`
type UpdateTemplateVersionFlagsByJobIDParams struct {
JobID uuid.UUID `db:"job_id" json:"job_id"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
func (q *sqlQuerier) UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg UpdateTemplateVersionFlagsByJobIDParams) error {
- _, err := q.db.ExecContext(ctx, updateTemplateVersionFlagsByJobID,
- arg.JobID,
- arg.HasAITask,
- arg.HasExternalAgent,
- arg.UpdatedAt,
- )
+ _, err := q.db.ExecContext(ctx, updateTemplateVersionFlagsByJobID, arg.JobID, arg.HasExternalAgent, arg.UpdatedAt)
return err
}
@@ -33990,7 +33968,7 @@ const getAuthenticatedWorkspaceAgentAndBuildByAuthToken = `-- name: GetAuthentic
SELECT
workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at, workspaces.dormant_at, workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, workspaces.next_start_at, workspaces.group_acl, workspaces.user_acl,
workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps, workspace_agents.api_version, workspace_agents.display_order, workspace_agents.parent_id, workspace_agents.api_key_scope, workspace_agents.deleted,
- workspace_build_with_user.id, workspace_build_with_user.created_at, workspace_build_with_user.updated_at, workspace_build_with_user.workspace_id, workspace_build_with_user.template_version_id, workspace_build_with_user.build_number, workspace_build_with_user.transition, workspace_build_with_user.initiator_id, workspace_build_with_user.job_id, workspace_build_with_user.deadline, workspace_build_with_user.reason, workspace_build_with_user.daily_cost, workspace_build_with_user.max_deadline, workspace_build_with_user.template_version_preset_id, workspace_build_with_user.has_ai_task, workspace_build_with_user.has_external_agent, workspace_build_with_user.notified_autostop_deadline, workspace_build_with_user.initiator_by_avatar_url, workspace_build_with_user.initiator_by_username, workspace_build_with_user.initiator_by_name,
+ workspace_build_with_user.id, workspace_build_with_user.created_at, workspace_build_with_user.updated_at, workspace_build_with_user.workspace_id, workspace_build_with_user.template_version_id, workspace_build_with_user.build_number, workspace_build_with_user.transition, workspace_build_with_user.initiator_id, workspace_build_with_user.job_id, workspace_build_with_user.deadline, workspace_build_with_user.reason, workspace_build_with_user.daily_cost, workspace_build_with_user.max_deadline, workspace_build_with_user.template_version_preset_id, workspace_build_with_user.has_external_agent, workspace_build_with_user.notified_autostop_deadline, workspace_build_with_user.initiator_by_avatar_url, workspace_build_with_user.initiator_by_username, workspace_build_with_user.initiator_by_name,
tasks.id AS task_id
FROM
workspace_agents
@@ -34134,7 +34112,6 @@ func (q *sqlQuerier) GetAuthenticatedWorkspaceAgentAndBuildByAuthToken(ctx conte
&i.WorkspaceBuild.DailyCost,
&i.WorkspaceBuild.MaxDeadline,
&i.WorkspaceBuild.TemplateVersionPresetID,
- &i.WorkspaceBuild.HasAITask,
&i.WorkspaceBuild.HasExternalAgent,
&i.WorkspaceBuild.NotifiedAutostopDeadline,
&i.WorkspaceBuild.InitiatorByAvatarUrl,
@@ -37673,7 +37650,7 @@ func (q *sqlQuerier) InsertWorkspaceBuildParameters(ctx context.Context, arg Ins
}
const getActiveWorkspaceBuildsByTemplateID = `-- name: GetActiveWorkspaceBuildsByTemplateID :many
-SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.has_external_agent, wb.notified_autostop_deadline, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name
+SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_external_agent, wb.notified_autostop_deadline, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name
FROM (
SELECT
workspace_id, MAX(build_number) as max_build_number
@@ -37727,7 +37704,6 @@ func (q *sqlQuerier) GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, t
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -37829,7 +37805,7 @@ func (q *sqlQuerier) GetFailedWorkspaceBuildsByTemplateID(ctx context.Context, a
const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one
SELECT
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -37858,7 +37834,6 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -37926,7 +37901,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildWithStatusByWorkspaceID(ctx context.
const getLatestWorkspaceBuildsByWorkspaceIDs = `-- name: GetLatestWorkspaceBuildsByWorkspaceIDs :many
SELECT
DISTINCT ON (workspace_id)
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -37959,7 +37934,6 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context,
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -37981,7 +37955,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context,
const getWorkspaceBuildByID = `-- name: GetWorkspaceBuildByID :one
SELECT
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -38008,7 +37982,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -38020,7 +37993,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W
const getWorkspaceBuildByJobID = `-- name: GetWorkspaceBuildByJobID :one
SELECT
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -38047,7 +38020,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -38059,7 +38031,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU
const getWorkspaceBuildByWorkspaceIDAndBuildNumber = `-- name: GetWorkspaceBuildByWorkspaceIDAndBuildNumber :one
SELECT
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -38090,7 +38062,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Co
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -38267,7 +38238,7 @@ func (q *sqlQuerier) GetWorkspaceBuildStatsByTemplates(ctx context.Context, sinc
const getWorkspaceBuildsByWorkspaceID = `-- name: GetWorkspaceBuildsByWorkspaceID :many
SELECT
- id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
+ id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name
FROM
workspace_build_with_user AS workspace_builds
WHERE
@@ -38337,7 +38308,6 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -38358,7 +38328,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge
}
const getWorkspaceBuildsCreatedAfter = `-- name: GetWorkspaceBuildsCreatedAfter :many
-SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user WHERE created_at > $1
+SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user WHERE created_at > $1
`
func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceBuild, error) {
@@ -38385,7 +38355,6 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created
&i.DailyCost,
&i.MaxDeadline,
&i.TemplateVersionPresetID,
- &i.HasAITask,
&i.HasExternalAgent,
&i.NotifiedAutostopDeadline,
&i.InitiatorByAvatarUrl,
@@ -38522,26 +38491,19 @@ const updateWorkspaceBuildFlagsByID = `-- name: UpdateWorkspaceBuildFlagsByID :e
UPDATE
workspace_builds
SET
- has_ai_task = $1,
- has_external_agent = $2,
- updated_at = $3::timestamptz
-WHERE id = $4::uuid
+ has_external_agent = $1,
+ updated_at = $2::timestamptz
+WHERE id = $3::uuid
`
type UpdateWorkspaceBuildFlagsByIDParams struct {
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
ID uuid.UUID `db:"id" json:"id"`
}
func (q *sqlQuerier) UpdateWorkspaceBuildFlagsByID(ctx context.Context, arg UpdateWorkspaceBuildFlagsByIDParams) error {
- _, err := q.db.ExecContext(ctx, updateWorkspaceBuildFlagsByID,
- arg.HasAITask,
- arg.HasExternalAgent,
- arg.UpdatedAt,
- arg.ID,
- )
+ _, err := q.db.ExecContext(ctx, updateWorkspaceBuildFlagsByID, arg.HasExternalAgent, arg.UpdatedAt, arg.ID)
return err
}
@@ -39808,7 +39770,6 @@ LEFT JOIN LATERAL (
workspace_builds.id,
workspace_builds.transition,
workspace_builds.template_version_id,
- workspace_builds.has_ai_task,
workspace_builds.has_external_agent,
template_versions.name AS template_version_name,
provisioner_jobs.id AS provisioner_job_id,
@@ -40029,43 +39990,28 @@ WHERE
(latest_build.template_version_id = template.active_version_id) = $19 :: boolean
ELSE true
END
- -- Filter by has_ai_task, checks if this is a task workspace.
- AND CASE
- WHEN $20::boolean IS NOT NULL
- THEN $20::boolean = EXISTS (
- SELECT
- 1
- FROM
- tasks
- WHERE
- -- Consider all tasks, deleting a task does not turn the
- -- workspace into a non-task workspace.
- tasks.workspace_id = workspaces.id
- )
- ELSE true
- END
-- Filter by has_external_agent in latest build
AND CASE
- WHEN $21 :: boolean IS NOT NULL THEN
- latest_build.has_external_agent = $21 :: boolean
+ WHEN $20 :: boolean IS NOT NULL THEN
+ latest_build.has_external_agent = $20 :: boolean
ELSE true
END
-- Filter by shared status
AND CASE
- WHEN $22 :: boolean IS NOT NULL THEN
- (workspaces.user_acl != '{}'::jsonb OR workspaces.group_acl != '{}'::jsonb) = $22 :: boolean
+ WHEN $21 :: boolean IS NOT NULL THEN
+ (workspaces.user_acl != '{}'::jsonb OR workspaces.group_acl != '{}'::jsonb) = $21 :: boolean
ELSE true
END
-- Filter by shared_with_user_id
AND CASE
- WHEN $23 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
- workspaces.user_acl ? ($23 :: uuid) :: text
+ WHEN $22 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
+ workspaces.user_acl ? ($22 :: uuid) :: text
ELSE true
END
-- Filter by shared_with_group_id
AND CASE
- WHEN $24 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
- workspaces.group_acl ? ($24 :: uuid) :: text
+ WHEN $23 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
+ workspaces.group_acl ? ($23 :: uuid) :: text
ELSE true
END
@@ -40078,7 +40024,7 @@ WHERE
filtered_workspaces fw
ORDER BY
-- To ensure that 'favorite' workspaces show up first in the list only for their owner.
- CASE WHEN favorite AND owner_username = (SELECT users.username FROM users WHERE users.id = $25) THEN 0 ELSE 1 END ASC,
+ CASE WHEN favorite AND owner_username = (SELECT users.username FROM users WHERE users.id = $24) THEN 0 ELSE 1 END ASC,
(latest_build_completed_at IS NOT NULL AND
latest_build_canceled_at IS NULL AND
latest_build_error IS NULL AND
@@ -40087,11 +40033,11 @@ WHERE
LOWER(name) ASC
LIMIT
CASE
- WHEN $27 :: integer > 0 THEN
- $27
+ WHEN $26 :: integer > 0 THEN
+ $26
END
OFFSET
- $26
+ $25
), filtered_workspaces_order_with_summary AS (
SELECT
fwo.id, fwo.created_at, fwo.updated_at, fwo.owner_id, fwo.organization_id, fwo.template_id, fwo.deleted, fwo.name, fwo.autostart_schedule, fwo.ttl, fwo.last_used_at, fwo.dormant_at, fwo.deleting_at, fwo.automatic_updates, fwo.favorite, fwo.next_start_at, fwo.group_acl, fwo.user_acl, fwo.owner_avatar_url, fwo.owner_username, fwo.owner_name, fwo.organization_name, fwo.organization_display_name, fwo.organization_icon, fwo.organization_description, fwo.template_name, fwo.template_display_name, fwo.template_icon, fwo.template_description, fwo.task_id, fwo.group_acl_display_info, fwo.user_acl_display_info, fwo.template_version_id, fwo.template_version_name, fwo.latest_build_completed_at, fwo.latest_build_canceled_at, fwo.latest_build_error, fwo.latest_build_transition, fwo.latest_build_status, fwo.latest_build_has_external_agent, fwo.latest_build_provisioner_job_id
@@ -40144,7 +40090,7 @@ WHERE
false, -- latest_build_has_external_agent
'00000000-0000-0000-0000-000000000000'::uuid -- latest_build_provisioner_job_id
WHERE
- $28 :: boolean = true
+ $27 :: boolean = true
), total_count AS (
SELECT
count(*) AS count
@@ -40233,7 +40179,6 @@ type GetWorkspacesParams struct {
LastUsedBefore time.Time `db:"last_used_before" json:"last_used_before"`
LastUsedAfter time.Time `db:"last_used_after" json:"last_used_after"`
UsingActive sql.NullBool `db:"using_active" json:"using_active"`
- HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"`
HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"`
Shared sql.NullBool `db:"shared" json:"shared"`
SharedWithUserID uuid.UUID `db:"shared_with_user_id" json:"shared_with_user_id"`
@@ -40314,7 +40259,6 @@ func (q *sqlQuerier) GetWorkspaces(ctx context.Context, arg GetWorkspacesParams)
arg.LastUsedBefore,
arg.LastUsedAfter,
arg.UsingActive,
- arg.HasAITask,
arg.HasExternalAgent,
arg.Shared,
arg.SharedWithUserID,
diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql
index ba4836086448c..d05c78a61ad3a 100644
--- a/coderd/database/queries/templates.sql
+++ b/coderd/database/queries/templates.sql
@@ -71,12 +71,6 @@ WHERE
END
ELSE true
END
- -- Filter by has_ai_task in latest version
- AND CASE
- WHEN sqlc.narg('has_ai_task') :: boolean IS NOT NULL THEN
- tv.has_ai_task = sqlc.narg('has_ai_task') :: boolean
- ELSE true
- END
-- Filter by agents_allowed
AND CASE
WHEN sqlc.narg('agents_allowed') :: boolean IS NOT NULL THEN
diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql
index e68383aa0632e..4813c0f83d92c 100644
--- a/coderd/database/queries/templateversions.sql
+++ b/coderd/database/queries/templateversions.sql
@@ -230,8 +230,7 @@ RETURNING template_versions.id;
UPDATE
template_versions
SET
- has_ai_task = $2,
- has_external_agent = $3,
- updated_at = $4
+ has_external_agent = $2,
+ updated_at = $3
WHERE
job_id = $1;
diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql
index 390ffefab9e01..7afe146d39791 100644
--- a/coderd/database/queries/workspacebuilds.sql
+++ b/coderd/database/queries/workspacebuilds.sql
@@ -252,7 +252,6 @@ ORDER BY
UPDATE
workspace_builds
SET
- has_ai_task = @has_ai_task,
has_external_agent = @has_external_agent,
updated_at = @updated_at::timestamptz
WHERE id = @id::uuid;
diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql
index 15251b56ca0a8..81d57c167f085 100644
--- a/coderd/database/queries/workspaces.sql
+++ b/coderd/database/queries/workspaces.sql
@@ -130,7 +130,6 @@ LEFT JOIN LATERAL (
workspace_builds.id,
workspace_builds.transition,
workspace_builds.template_version_id,
- workspace_builds.has_ai_task,
workspace_builds.has_external_agent,
template_versions.name AS template_version_name,
provisioner_jobs.id AS provisioner_job_id,
@@ -351,21 +350,6 @@ WHERE
(latest_build.template_version_id = template.active_version_id) = sqlc.narg('using_active') :: boolean
ELSE true
END
- -- Filter by has_ai_task, checks if this is a task workspace.
- AND CASE
- WHEN sqlc.narg('has_ai_task')::boolean IS NOT NULL
- THEN sqlc.narg('has_ai_task')::boolean = EXISTS (
- SELECT
- 1
- FROM
- tasks
- WHERE
- -- Consider all tasks, deleting a task does not turn the
- -- workspace into a non-task workspace.
- tasks.workspace_id = workspaces.id
- )
- ELSE true
- END
-- Filter by has_external_agent in latest build
AND CASE
WHEN sqlc.narg('has_external_agent') :: boolean IS NOT NULL THEN
diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go
index 2052edd2c0b63..771b121a6d138 100644
--- a/coderd/provisionerdserver/provisionerdserver.go
+++ b/coderd/provisionerdserver/provisionerdserver.go
@@ -2038,9 +2038,6 @@ func (s *server) completeTemplateImportJob(ctx context.Context, job database.Pro
}
err = db.UpdateTemplateVersionFlagsByJobID(ctx, database.UpdateTemplateVersionFlagsByJobIDParams{
JobID: jobID,
- // Tasks are removed; the has_ai_task column is dropped in a
- // follow-up migration.
- HasAITask: sql.NullBool{Bool: false, Valid: true},
HasExternalAgent: sql.NullBool{
Bool: jobType.TemplateImport.HasExternalAgents,
Valid: true,
@@ -2320,9 +2317,6 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
})
if err := db.UpdateWorkspaceBuildFlagsByID(ctx, database.UpdateWorkspaceBuildFlagsByIDParams{
ID: workspaceBuild.ID,
- // Tasks are removed; the has_ai_task column is dropped in a
- // follow-up migration.
- HasAITask: sql.NullBool{Bool: false, Valid: true},
HasExternalAgent: sql.NullBool{
Bool: hasExternalAgent,
Valid: true,
diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md
index c2e4d884b2bfa..8bfca3fe8b4da 100644
--- a/docs/admin/security/audit-logs.md
+++ b/docs/admin/security/audit-logs.md
@@ -45,11 +45,11 @@ We track the following resources:
| PrebuildsSettings
|
| Field | Tracked |
| | id | false |
| reconciliation_paused | true |
|
| RoleSyncSettings
| | Field | Tracked |
| | field | true |
| mapping | true |
|
| Template
write, delete | | Field | Tracked |
| | active_version_id | true |
| activity_bump | true |
| agents_allowed | true |
| allow_user_autostart | true |
| allow_user_autostop | true |
| allow_user_cancel_workspace_jobs | true |
| allow_workspace_renames | true |
| autostart_block_days_of_week | true |
| autostop_requirement_days_of_week | true |
| autostop_requirement_weeks | true |
| cors_behavior | true |
| created_at | false |
| created_by | true |
| created_by_avatar_url | false |
| created_by_name | false |
| created_by_username | false |
| default_ttl | true |
| deleted | false |
| deprecated | true |
| description | true |
| disable_module_cache | true |
| display_name | true |
| failure_ttl | true |
| group_acl | true |
| icon | true |
| id | true |
| max_port_sharing_level | true |
| name | true |
| organization_display_name | false |
| organization_icon | false |
| organization_id | false |
| organization_name | false |
| provisioner | true |
| require_active_version | true |
| time_til_autostop_notify | true |
| time_til_dormant | true |
| time_til_dormant_autodelete | true |
| updated_at | false |
| use_classic_parameter_flow | true |
| user_acl | true |
|
-| TemplateVersion
create, write | | Field | Tracked |
| | archived | true |
| created_at | false |
| created_by | true |
| created_by_avatar_url | false |
| created_by_name | false |
| created_by_username | false |
| external_auth_providers | false |
| has_ai_task | false |
| has_external_agent | false |
| id | true |
| job_id | false |
| message | false |
| name | true |
| organization_id | false |
| readme | true |
| source_example_id | false |
| template_id | true |
| updated_at | false |
|
+| TemplateVersion
create, write | | Field | Tracked |
| | archived | true |
| created_at | false |
| created_by | true |
| created_by_avatar_url | false |
| created_by_name | false |
| created_by_username | false |
| external_auth_providers | false |
| has_external_agent | false |
| id | true |
| job_id | false |
| message | false |
| name | true |
| organization_id | false |
| readme | true |
| source_example_id | false |
| template_id | true |
| updated_at | false |
|
| User
create, write, delete | | Field | Tracked |
| | avatar_url | false |
| chat_spend_limit_micros | true |
| created_at | false |
| deleted | true |
| email | true |
| github_com_user_id | false |
| hashed_one_time_passcode | false |
| hashed_password | true |
| id | true |
| is_service_account | true |
| is_system | true |
| last_seen_at | false |
| login_type | true |
| name | true |
| one_time_passcode_expires_at | true |
| quiet_hours_schedule | true |
| rbac_roles | true |
| status | true |
| updated_at | false |
| username | true |
|
| UserSecret
create, write, delete | | Field | Tracked |
| | created_at | false |
| description | true |
| enabled | true |
| env_name | true |
| file_path | true |
| id | true |
| name | true |
| updated_at | false |
| user_id | true |
| value | true |
| value_key_id | false |
|
| UserSkill
create, write, delete | | Field | Tracked |
| | content | true |
| created_at | false |
| description | true |
| id | true |
| name | true |
| updated_at | false |
| user_id | true |
|
-| WorkspaceBuild
start, stop | | Field | Tracked |
| | build_number | false |
| created_at | false |
| daily_cost | false |
| deadline | false |
| has_ai_task | false |
| has_external_agent | false |
| id | false |
| initiator_by_avatar_url | false |
| initiator_by_name | false |
| initiator_by_username | false |
| initiator_id | false |
| job_id | false |
| max_deadline | false |
| notified_autostop_deadline | false |
| reason | false |
| template_version_id | true |
| template_version_preset_id | false |
| transition | false |
| updated_at | false |
| workspace_id | false |
|
+| WorkspaceBuild
start, stop | | Field | Tracked |
| | build_number | false |
| created_at | false |
| daily_cost | false |
| deadline | false |
| has_external_agent | false |
| id | false |
| initiator_by_avatar_url | false |
| initiator_by_name | false |
| initiator_by_username | false |
| initiator_id | false |
| job_id | false |
| max_deadline | false |
| notified_autostop_deadline | false |
| reason | false |
| template_version_id | true |
| template_version_preset_id | false |
| transition | false |
| updated_at | false |
| workspace_id | false |
|
| WorkspaceProxy
| | Field | Tracked |
| | created_at | true |
| deleted | false |
| derp_enabled | true |
| derp_only | true |
| display_name | true |
| icon | true |
| id | true |
| name | true |
| region_id | true |
| token_hashed_secret | true |
| updated_at | false |
| url | true |
| version | true |
| wildcard_hostname | true |
|
| WorkspaceTable
| | Field | Tracked |
| | automatic_updates | true |
| autostart_schedule | true |
| created_at | false |
| deleted | false |
| deleting_at | true |
| dormant_at | true |
| favorite | true |
| group_acl | true |
| id | true |
| last_used_at | false |
| name | true |
| next_start_at | true |
| organization_id | false |
| owner_id | true |
| template_id | true |
| ttl | true |
| updated_at | false |
| user_acl | true |
|
diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go
index e4339af2507ce..823db47223d5a 100644
--- a/enterprise/audit/table.go
+++ b/enterprise/audit/table.go
@@ -154,7 +154,6 @@ var auditableResourcesTypes = map[any]map[string]Action{
"created_by_name": ActionIgnore,
"archived": ActionTrack,
"source_example_id": ActionIgnore, // Never changes.
- "has_ai_task": ActionIgnore, // Never changes.
"has_external_agent": ActionIgnore, // Never changes.
},
&database.User{}: {
@@ -217,7 +216,6 @@ var auditableResourcesTypes = map[any]map[string]Action{
"initiator_by_username": ActionIgnore,
"initiator_by_name": ActionIgnore,
"template_version_preset_id": ActionIgnore, // Never changes.
- "has_ai_task": ActionIgnore, // Never changes.
"has_external_agent": ActionIgnore, // Never changes.
"notified_autostop_deadline": ActionIgnore, // Updated by the notification system, not by user action.
},
From 5fc53ee9538d0cddda5731825703ed1306ee0253 Mon Sep 17 00:00:00 2001
From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com>
Date: Fri, 11 Sep 2026 00:08:42 +0000
Subject: [PATCH 2/2] fix(coderd/database/migrations): renumber to 000593 and
drop schema assertions from the test
---
...s_ai_task_and_task_build_reasons.down.sql} | 0
...has_ai_task_and_task_build_reasons.up.sql} | 0
coderd/database/migrations/migrate_test.go | 29 ++++---------------
3 files changed, 6 insertions(+), 23 deletions(-)
rename coderd/database/migrations/{000592_remove_has_ai_task_and_task_build_reasons.down.sql => 000593_remove_has_ai_task_and_task_build_reasons.down.sql} (100%)
rename coderd/database/migrations/{000592_remove_has_ai_task_and_task_build_reasons.up.sql => 000593_remove_has_ai_task_and_task_build_reasons.up.sql} (100%)
diff --git a/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.down.sql
similarity index 100%
rename from coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.down.sql
rename to coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.down.sql
diff --git a/coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.up.sql
similarity index 100%
rename from coderd/database/migrations/000592_remove_has_ai_task_and_task_build_reasons.up.sql
rename to coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.up.sql
diff --git a/coderd/database/migrations/migrate_test.go b/coderd/database/migrations/migrate_test.go
index 27af55f0799a8..19457e9ce9f37 100644
--- a/coderd/database/migrations/migrate_test.go
+++ b/coderd/database/migrations/migrate_test.go
@@ -1190,10 +1190,10 @@ func TestMigration000475AgentsAccessOrgRole(t *testing.T) {
)
}
-func TestMigration000592RemoveHasAITaskAndTaskBuildReasons(t *testing.T) {
+func TestMigration000593RemoveHasAITaskAndTaskBuildReasons(t *testing.T) {
t.Parallel()
- const migrationVersion = 592
+ const migrationVersion = 593
sqlDB := testSQLDB(t)
next, err := migrations.Stepper(sqlDB)
require.NoError(t, err)
@@ -1269,12 +1269,6 @@ func TestMigration000592RemoveHasAITaskAndTaskBuildReasons(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, migrationVersion, version)
var count int
- const columnsQuery = "SELECT count(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name IN ('template_versions', 'workspace_builds') AND column_name = 'has_ai_task'"
- require.NoError(t, sqlDB.QueryRowContext(ctx, columnsQuery).Scan(&count))
- require.Zero(t, count)
- const indexQuery = "SELECT count(*) FROM pg_indexes WHERE schemaname = 'public' AND indexname = 'idx_template_versions_has_ai_task'"
- require.NoError(t, sqlDB.QueryRowContext(ctx, indexQuery).Scan(&count))
- require.Zero(t, count)
var reasons pq.StringArray
const reasonsQuery = "SELECT array_agg(reason::text ORDER BY build_number) FROM workspace_builds WHERE workspace_id = $1"
wantReasons := pq.StringArray{"autostop", "initiator", "initiator", "initiator", "autostop"}
@@ -1283,43 +1277,32 @@ func TestMigration000592RemoveHasAITaskAndTaskBuildReasons(t *testing.T) {
var childReason string
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason))
require.Equal(t, "autostop", childReason)
- var enumValues pq.StringArray
- const enumQuery = "SELECT enum_range(NULL::build_reason)::text[]"
- require.NoError(t, sqlDB.QueryRowContext(ctx, enumQuery).Scan(&enumValues))
- wantEnum := pq.StringArray{"initiator", "autostart", "autostop", "dormancy", "failedstop", "autodelete", "dashboard", "cli", "ssh_connection", "vscode_connection", "jetbrains_connection"}
- require.Equal(t, wantEnum, enumValues)
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_version_with_user").Scan(&count))
require.Equal(t, 1, count)
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_build_with_user").Scan(&count))
require.Equal(t, len(buildIDs), count)
- downSQL, err := os.ReadFile("000592_remove_has_ai_task_and_task_build_reasons.down.sql")
+ downSQL, err := os.ReadFile("000593_remove_has_ai_task_and_task_build_reasons.down.sql")
require.NoError(t, err)
_, err = sqlDB.ExecContext(ctx, string(downSQL))
require.NoError(t, err)
- require.NoError(t, sqlDB.QueryRowContext(ctx, columnsQuery).Scan(&count))
- require.Equal(t, 2, count)
- require.NoError(t, sqlDB.QueryRowContext(ctx, indexQuery).Scan(&count))
- require.Equal(t, 1, count)
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_versions WHERE has_ai_task IS FALSE").Scan(&count))
require.Equal(t, 1, count)
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_builds WHERE has_ai_task IS FALSE").Scan(&count))
require.Equal(t, len(buildIDs), count)
- require.NoError(t, sqlDB.QueryRowContext(ctx, enumQuery).Scan(&enumValues))
- require.Equal(t, append(wantEnum, "task_auto_pause", "task_manual_pause", "task_resume"), enumValues)
// The original reasons cannot be recovered after remapping.
require.NoError(t, sqlDB.QueryRowContext(ctx, reasonsQuery, workspaceID).Scan(&reasons))
require.Equal(t, wantReasons, reasons)
require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason))
require.Equal(t, "autostop", childReason)
- upSQL, err := os.ReadFile("000592_remove_has_ai_task_and_task_build_reasons.up.sql")
+ upSQL, err := os.ReadFile("000593_remove_has_ai_task_and_task_build_reasons.up.sql")
require.NoError(t, err)
_, err = sqlDB.ExecContext(ctx, string(upSQL))
require.NoError(t, err)
}
-func TestMigration000592TaskBuildReasonRewriteTiming(t *testing.T) {
+func TestMigration000593TaskBuildReasonRewriteTiming(t *testing.T) {
t.Parallel()
if testing.Short() {
@@ -1330,7 +1313,7 @@ func TestMigration000592TaskBuildReasonRewriteTiming(t *testing.T) {
// The enum replacement rewrites workspace_builds, risking slow upgrades
// on large deployments.
const (
- migrationVersion = 592
+ migrationVersion = 593
workspaceCount = 1_000
buildCount = 100_000
buildsPerWorkspace = buildCount / workspaceCount