feat: add crystallizes column to sqlite storage

Adds crystallizes column for work economics (compounds vs evaporates)
per Decision 006. Includes migration 036 and updates to all INSERT/SELECT
queries in issues.go, queries.go, dependencies.go, and transaction.go.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beads/crew/fang
2026-01-10 23:42:58 -08:00
committed by Steve Yegge
parent 0ed349b3ed
commit f5cd36752d
6 changed files with 97 additions and 17 deletions

View File

@@ -249,7 +249,7 @@ func (s *SQLiteStorage) GetDependenciesWithMetadata(ctx context.Context, issueID
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes, i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
i.created_at, i.created_by, i.owner, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.created_at, i.created_by, i.owner, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type, i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
i.sender, i.ephemeral, i.pinned, i.is_template, i.sender, i.ephemeral, i.pinned, i.is_template, i.crystallizes,
i.await_type, i.await_id, i.timeout_ns, i.waiters, i.await_type, i.await_id, i.timeout_ns, i.waiters,
d.type d.type
FROM issues i FROM issues i
@@ -272,7 +272,7 @@ func (s *SQLiteStorage) GetDependentsWithMetadata(ctx context.Context, issueID s
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes, i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
i.created_at, i.created_by, i.owner, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.created_at, i.created_by, i.owner, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type, i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
i.sender, i.ephemeral, i.pinned, i.is_template, i.sender, i.ephemeral, i.pinned, i.is_template, i.crystallizes,
i.await_type, i.await_id, i.timeout_ns, i.waiters, i.await_type, i.await_id, i.timeout_ns, i.waiters,
d.type d.type
FROM issues i FROM issues i
@@ -879,6 +879,8 @@ func (s *SQLiteStorage) scanIssues(ctx context.Context, rows *sql.Rows) ([]*type
var pinned sql.NullInt64 var pinned sql.NullInt64
// Template field // Template field
var isTemplate sql.NullInt64 var isTemplate sql.NullInt64
// Crystallizes field (work economics)
var crystallizes sql.NullInt64
// Gate fields // Gate fields
var awaitType sql.NullString var awaitType sql.NullString
var awaitID sql.NullString var awaitID sql.NullString
@@ -891,7 +893,7 @@ func (s *SQLiteStorage) scanIssues(ctx context.Context, rows *sql.Rows) ([]*type
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes, &issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
&issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &closeReason, &issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &closeReason,
&deletedAt, &deletedBy, &deleteReason, &originalType, &deletedAt, &deletedBy, &deleteReason, &originalType,
&sender, &wisp, &pinned, &isTemplate, &sender, &wisp, &pinned, &isTemplate, &crystallizes,
&awaitType, &awaitID, &timeoutNs, &waiters, &awaitType, &awaitID, &timeoutNs, &waiters,
) )
if err != nil { if err != nil {
@@ -948,6 +950,10 @@ func (s *SQLiteStorage) scanIssues(ctx context.Context, rows *sql.Rows) ([]*type
if isTemplate.Valid && isTemplate.Int64 != 0 { if isTemplate.Valid && isTemplate.Int64 != 0 {
issue.IsTemplate = true issue.IsTemplate = true
} }
// Crystallizes field (work economics)
if crystallizes.Valid && crystallizes.Int64 != 0 {
issue.Crystallizes = true
}
// Gate fields // Gate fields
if awaitType.Valid { if awaitType.Valid {
issue.AwaitType = awaitType.String issue.AwaitType = awaitType.String
@@ -1005,6 +1011,8 @@ func (s *SQLiteStorage) scanIssuesWithDependencyType(ctx context.Context, rows *
var pinned sql.NullInt64 var pinned sql.NullInt64
// Template field // Template field
var isTemplate sql.NullInt64 var isTemplate sql.NullInt64
// Crystallizes field (work economics)
var crystallizes sql.NullInt64
// Gate fields // Gate fields
var awaitType sql.NullString var awaitType sql.NullString
var awaitID sql.NullString var awaitID sql.NullString
@@ -1018,7 +1026,7 @@ func (s *SQLiteStorage) scanIssuesWithDependencyType(ctx context.Context, rows *
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes, &issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
&issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo,
&deletedAt, &deletedBy, &deleteReason, &originalType, &deletedAt, &deletedBy, &deleteReason, &originalType,
&sender, &wisp, &pinned, &isTemplate, &sender, &wisp, &pinned, &isTemplate, &crystallizes,
&awaitType, &awaitID, &timeoutNs, &waiters, &awaitType, &awaitID, &timeoutNs, &waiters,
&depType, &depType,
) )
@@ -1073,6 +1081,10 @@ func (s *SQLiteStorage) scanIssuesWithDependencyType(ctx context.Context, rows *
if isTemplate.Valid && isTemplate.Int64 != 0 { if isTemplate.Valid && isTemplate.Int64 != 0 {
issue.IsTemplate = true issue.IsTemplate = true
} }
// Crystallizes field (work economics)
if crystallizes.Valid && crystallizes.Int64 != 0 {
issue.Crystallizes = true
}
// Gate fields // Gate fields
if awaitType.Valid { if awaitType.Valid {
issue.AwaitType = awaitType.String issue.AwaitType = awaitType.String

View File

@@ -41,6 +41,10 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
if issue.IsTemplate { if issue.IsTemplate {
isTemplate = 1 isTemplate = 1
} }
crystallizes := 0
if issue.Crystallizes {
crystallizes = 1
}
_, err := conn.ExecContext(ctx, ` _, err := conn.ExecContext(ctx, `
INSERT OR IGNORE INTO issues ( INSERT OR IGNORE INTO issues (
@@ -48,7 +52,7 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
status, priority, issue_type, assignee, estimated_minutes, status, priority, issue_type, assignee, estimated_minutes,
created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason, created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters, mol_type, await_type, await_id, timeout_ns, waiters, mol_type,
event_kind, actor, target, payload, event_kind, actor, target, payload,
due_at, defer_until due_at, defer_until
@@ -60,7 +64,7 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt, issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt,
issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason, issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason,
issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType, issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType,
issue.Sender, wisp, pinned, isTemplate, issue.Sender, wisp, pinned, isTemplate, crystallizes,
issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters), issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters),
string(issue.MolType), string(issue.MolType),
issue.EventKind, issue.Actor, issue.Target, issue.Payload, issue.EventKind, issue.Actor, issue.Target, issue.Payload,
@@ -99,6 +103,10 @@ func insertIssueStrict(ctx context.Context, conn *sql.Conn, issue *types.Issue)
if issue.IsTemplate { if issue.IsTemplate {
isTemplate = 1 isTemplate = 1
} }
crystallizes := 0
if issue.Crystallizes {
crystallizes = 1
}
_, err := conn.ExecContext(ctx, ` _, err := conn.ExecContext(ctx, `
INSERT INTO issues ( INSERT INTO issues (
@@ -106,7 +114,7 @@ func insertIssueStrict(ctx context.Context, conn *sql.Conn, issue *types.Issue)
status, priority, issue_type, assignee, estimated_minutes, status, priority, issue_type, assignee, estimated_minutes,
created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason, created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters, mol_type, await_type, await_id, timeout_ns, waiters, mol_type,
event_kind, actor, target, payload, event_kind, actor, target, payload,
due_at, defer_until due_at, defer_until
@@ -118,7 +126,7 @@ func insertIssueStrict(ctx context.Context, conn *sql.Conn, issue *types.Issue)
issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt, issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt,
issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason, issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason,
issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType, issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType,
issue.Sender, wisp, pinned, isTemplate, issue.Sender, wisp, pinned, isTemplate, crystallizes,
issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters), issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters),
string(issue.MolType), string(issue.MolType),
issue.EventKind, issue.Actor, issue.Target, issue.Payload, issue.EventKind, issue.Actor, issue.Target, issue.Payload,
@@ -138,7 +146,7 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
status, priority, issue_type, assignee, estimated_minutes, status, priority, issue_type, assignee, estimated_minutes,
created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason, created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters, mol_type, await_type, await_id, timeout_ns, waiters, mol_type,
event_kind, actor, target, payload, event_kind, actor, target, payload,
due_at, defer_until due_at, defer_until
@@ -167,6 +175,10 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
if issue.IsTemplate { if issue.IsTemplate {
isTemplate = 1 isTemplate = 1
} }
crystallizes := 0
if issue.Crystallizes {
crystallizes = 1
}
_, err = stmt.ExecContext(ctx, _, err = stmt.ExecContext(ctx,
issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design, issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design,
@@ -175,7 +187,7 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt, issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt,
issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason, issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason,
issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType, issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType,
issue.Sender, wisp, pinned, isTemplate, issue.Sender, wisp, pinned, isTemplate, crystallizes,
issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters), issue.AwaitType, issue.AwaitID, int64(issue.Timeout), formatJSONStringArray(issue.Waiters),
string(issue.MolType), string(issue.MolType),
issue.EventKind, issue.Actor, issue.Target, issue.Payload, issue.EventKind, issue.Actor, issue.Target, issue.Payload,

View File

@@ -0,0 +1,36 @@
package migrations
import (
"database/sql"
"fmt"
)
// MigrateCrystallizesColumn adds the crystallizes column to the issues table.
// Crystallizes tracks whether work compounds over time (true: code, features)
// or evaporates (false: ops, support). Per Decision 006, this affects CV weighting.
// Default is false (conservative - work evaporates unless explicitly marked).
func MigrateCrystallizesColumn(db *sql.DB) error {
// Check if column already exists
var columnExists bool
err := db.QueryRow(`
SELECT COUNT(*) > 0
FROM pragma_table_info('issues')
WHERE name = 'crystallizes'
`).Scan(&columnExists)
if err != nil {
return fmt.Errorf("failed to check crystallizes column: %w", err)
}
if columnExists {
// Column already exists (e.g. created by new schema)
return nil
}
// Add the crystallizes column
_, err = db.Exec(`ALTER TABLE issues ADD COLUMN crystallizes INTEGER DEFAULT 0`)
if err != nil {
return fmt.Errorf("failed to add crystallizes column: %w", err)
}
return nil
}

View File

@@ -273,6 +273,8 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
var pinned sql.NullInt64 var pinned sql.NullInt64
// Template field // Template field
var isTemplate sql.NullInt64 var isTemplate sql.NullInt64
// Crystallizes field (work economics)
var crystallizes sql.NullInt64
// Gate fields // Gate fields
var awaitType sql.NullString var awaitType sql.NullString
var awaitID sql.NullString var awaitID sql.NullString
@@ -305,7 +307,7 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
created_at, created_by, owner, updated_at, closed_at, external_ref, created_at, created_by, owner, updated_at, closed_at, external_ref,
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason, compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters, await_type, await_id, timeout_ns, waiters,
hook_bead, role_bead, agent_state, last_activity, role_type, rig, mol_type, hook_bead, role_bead, agent_state, last_activity, role_type, rig, mol_type,
event_kind, actor, target, payload, event_kind, actor, target, payload,
@@ -319,7 +321,7 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
&issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef,
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason, &issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
&deletedAt, &deletedBy, &deleteReason, &originalType, &deletedAt, &deletedBy, &deleteReason, &originalType,
&sender, &wisp, &pinned, &isTemplate, &sender, &wisp, &pinned, &isTemplate, &crystallizes,
&awaitType, &awaitID, &timeoutNs, &waiters, &awaitType, &awaitID, &timeoutNs, &waiters,
&hookBead, &roleBead, &agentState, &lastActivity, &roleType, &rig, &molType, &hookBead, &roleBead, &agentState, &lastActivity, &roleType, &rig, &molType,
&eventKind, &actor, &target, &payload, &eventKind, &actor, &target, &payload,
@@ -392,6 +394,10 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
if isTemplate.Valid && isTemplate.Int64 != 0 { if isTemplate.Valid && isTemplate.Int64 != 0 {
issue.IsTemplate = true issue.IsTemplate = true
} }
// Crystallizes field (work economics)
if crystallizes.Valid && crystallizes.Int64 != 0 {
issue.Crystallizes = true
}
// Gate fields // Gate fields
if awaitType.Valid { if awaitType.Valid {
issue.AwaitType = awaitType.String issue.AwaitType = awaitType.String
@@ -558,6 +564,8 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
var pinned sql.NullInt64 var pinned sql.NullInt64
// Template field // Template field
var isTemplate sql.NullInt64 var isTemplate sql.NullInt64
// Crystallizes field (work economics)
var crystallizes sql.NullInt64
// Gate fields // Gate fields
var awaitType sql.NullString var awaitType sql.NullString
var awaitID sql.NullString var awaitID sql.NullString
@@ -571,7 +579,7 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
created_at, created_by, owner, updated_at, closed_at, external_ref, created_at, created_by, owner, updated_at, closed_at, external_ref,
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason, compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters await_type, await_id, timeout_ns, waiters
FROM issues FROM issues
WHERE external_ref = ? WHERE external_ref = ?
@@ -582,7 +590,7 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
&issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRefCol, &issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRefCol,
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason, &issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
&deletedAt, &deletedBy, &deleteReason, &originalType, &deletedAt, &deletedBy, &deleteReason, &originalType,
&sender, &wisp, &pinned, &isTemplate, &sender, &wisp, &pinned, &isTemplate, &crystallizes,
&awaitType, &awaitID, &timeoutNs, &waiters, &awaitType, &awaitID, &timeoutNs, &waiters,
) )
@@ -652,6 +660,10 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
if isTemplate.Valid && isTemplate.Int64 != 0 { if isTemplate.Valid && isTemplate.Int64 != 0 {
issue.IsTemplate = true issue.IsTemplate = true
} }
// Crystallizes field (work economics)
if crystallizes.Valid && crystallizes.Int64 != 0 {
issue.Crystallizes = true
}
// Gate fields // Gate fields
if awaitType.Valid { if awaitType.Valid {
issue.AwaitType = awaitType.String issue.AwaitType = awaitType.String
@@ -1938,7 +1950,7 @@ func (s *SQLiteStorage) SearchIssues(ctx context.Context, query string, filter t
status, priority, issue_type, assignee, estimated_minutes, status, priority, issue_type, assignee, estimated_minutes,
created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason, created_at, created_by, owner, updated_at, closed_at, external_ref, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters await_type, await_id, timeout_ns, waiters
FROM issues FROM issues
%s %s

View File

@@ -37,6 +37,8 @@ CREATE TABLE IF NOT EXISTS issues (
pinned INTEGER DEFAULT 0, pinned INTEGER DEFAULT 0,
-- Template field (beads-1ra) -- Template field (beads-1ra)
is_template INTEGER DEFAULT 0, is_template INTEGER DEFAULT 0,
-- Work economics field (bd-fqze8) - HOP Decision 006
crystallizes INTEGER DEFAULT 0,
-- Molecule type field (bd-oxgi) -- Molecule type field (bd-oxgi)
mol_type TEXT DEFAULT '', mol_type TEXT DEFAULT '',
-- Work type field (Decision 006: mutex vs open_competition) -- Work type field (Decision 006: mutex vs open_competition)

View File

@@ -330,7 +330,7 @@ func (t *sqliteTxStorage) GetIssue(ctx context.Context, id string) (*types.Issue
created_at, created_by, owner, updated_at, closed_at, external_ref, created_at, created_by, owner, updated_at, closed_at, external_ref,
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason, compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
deleted_at, deleted_by, delete_reason, original_type, deleted_at, deleted_by, delete_reason, original_type,
sender, ephemeral, pinned, is_template, sender, ephemeral, pinned, is_template, crystallizes,
await_type, await_id, timeout_ns, waiters await_type, await_id, timeout_ns, waiters
FROM issues FROM issues
WHERE id = ? WHERE id = ?
@@ -1308,6 +1308,8 @@ func scanIssueRow(row scanner) (*types.Issue, error) {
var pinned sql.NullInt64 var pinned sql.NullInt64
// Template field // Template field
var isTemplate sql.NullInt64 var isTemplate sql.NullInt64
// Crystallizes field (work economics)
var crystallizes sql.NullInt64
// Gate fields // Gate fields
var awaitType sql.NullString var awaitType sql.NullString
var awaitID sql.NullString var awaitID sql.NullString
@@ -1321,7 +1323,7 @@ func scanIssueRow(row scanner) (*types.Issue, error) {
&issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef, &issue.CreatedAt, &issue.CreatedBy, &owner, &issue.UpdatedAt, &closedAt, &externalRef,
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason, &issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
&deletedAt, &deletedBy, &deleteReason, &originalType, &deletedAt, &deletedBy, &deleteReason, &originalType,
&sender, &wisp, &pinned, &isTemplate, &sender, &wisp, &pinned, &isTemplate, &crystallizes,
&awaitType, &awaitID, &timeoutNs, &waiters, &awaitType, &awaitID, &timeoutNs, &waiters,
) )
if err != nil { if err != nil {
@@ -1387,6 +1389,10 @@ func scanIssueRow(row scanner) (*types.Issue, error) {
if isTemplate.Valid && isTemplate.Int64 != 0 { if isTemplate.Valid && isTemplate.Int64 != 0 {
issue.IsTemplate = true issue.IsTemplate = true
} }
// Crystallizes field (work economics)
if crystallizes.Valid && crystallizes.Int64 != 0 {
issue.Crystallizes = true
}
// Gate fields // Gate fields
if awaitType.Valid { if awaitType.Valid {
issue.AwaitType = awaitType.String issue.AwaitType = awaitType.String