Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE KEYSPACE IF NOT EXISTS nvcf_autoscaler WITH replication = {'class': 'NetworkTopologyStrategy', 'ncp': '${REPLICA_COUNT}' } AND durable_writes = true;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE ROLE IF NOT EXISTS nvcf_autoscaler_app_access;
GRANT SELECT, MODIFY on keyspace nvcf_autoscaler to nvcf_autoscaler_app_access;
GRANT SELECT on keyspace system to nvcf_autoscaler_app_access;

CREATE ROLE IF NOT EXISTS nvcf_autoscaler_app_v0 with login = true and password = '${SERVICE_ROLE_PASSWORD}';

INSERT INTO system_auth.role_members (role, member) VALUES ('nvcf_autoscaler_app_access', 'nvcf_autoscaler_app_v0');
UPDATE system_auth.roles SET member_of = member_of + {'nvcf_autoscaler_app_access'} where role = 'nvcf_autoscaler_app_v0';
Comment on lines +7 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== AGENTS =='
find .. -name AGENTS.md -print

echo '== Relevant files =='
for f in \
  migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql \
  migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql \
  migrations/cassandra/keyspaces/nvcf_autoscaler/03_init_tables.up.sql \
  migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql \
  docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md
do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    cat -n "$f" | sed -n '1,220p'
  fi
done

echo '== Search for role management guidance =='
rg -n "GRANT ROLE|role_members|system_auth|member_of|role management|GRANT .* TO" migrations docs -S

Repository: NVIDIA/nvcf

Length of output: 15668


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== 02_init_roles.up.sql files =='
for f in migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql; do
  echo "--- $f ---"
  cat -n "$f"
done

echo '== Cassandra schema docs mentions =='
rg -n "system_auth|role_members|member_of|GRANT ROLE|CREATE ROLE|REVOKE ROLE|CQL security|roles" docs migrations -S

echo '== file sizes =='
wc -l migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql

Repository: NVIDIA/nvcf

Length of output: 12436


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== AGENTS under repo =='
for f in AGENTS.md infra/cassandra/AGENTS.md migrations/cassandra/AGENTS.md migrations/cassandra/keyspaces/AGENTS.md; do
  if [ -f "$f" ]; then
    echo "--- $f ($(wc -l < "$f") lines) ---"
    cat -n "$f" | sed -n '1,220p'
  fi
done

echo '== migrations/cassandra/README.md relevant lines =='
if [ -f migrations/cassandra/README.md ]; then
  cat -n migrations/cassandra/README.md | sed -n '130,180p'
fi

echo '== search for GRANT ROLE / role_members in docs and migrations =='
rg -n "GRANT ROLE|role_members|system_auth\.roles|system_auth\.role_members|member_of =" migrations/cassandra docs -S

Repository: NVIDIA/nvcf

Length of output: 18466


🌐 Web query:

Apache Cassandra role management GRANT ROLE system_auth.role_members documentation

💡 Result:

In Apache Cassandra, the GRANT ROLE statement is used to assign one role to another, establishing a hierarchical relationship where the grantee inherits the permissions of the granted role [1][2]. Role management is handled by the IRoleManager interface, and the default implementation, CassandraRoleManager, persists this information within the system_auth keyspace [3][4][5]. Specifically, the system_auth.role_members table acts as the lookup table that tracks these role-to-role grants [6][5][7]. Key points regarding GRANT ROLE and system_auth.role_members: 1. Syntax: The CQL statement follows the format GRANT role_name TO role_name [1][8]. 2. Functionality: Roles are modeled as a directed acyclic graph (DAG) [1][2]. When a role is granted to another, the grantee acquires all permissions associated with the granted role [1][2]. Circular grants are strictly prohibited by the system [1][8]. 3. Data Storage: The system_auth.role_members table is defined with the following schema: CREATE TABLE system_auth.role_members ( role text, member text, PRIMARY KEY(role, member)); This table stores the mapping of roles to their members (the roles that have been granted to them) [6][5]. While the GRANT ROLE command provides the primary interface for managing these relationships, the system_auth.role_members table is the internal persistent storage mechanism used by the default CassandraRoleManager [4][5]. Direct modification of system tables is generally discouraged in favor of using standard CQL commands [1][9].

Citations:


Use GRANT ... TO ... for role membership.
Replace the system_auth.role_members insert and system_auth.roles.member_of update in both migrations with Cassandra’s supported role-grant statement.

  • migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql
  • migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql

GRANT <role> TO <role> is the supported CQL path; writing system_auth directly ties the migration to Cassandra internals.

📍 Affects 2 files
  • migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql#L7-L8 (this comment)
  • migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql#L7-L8
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql` around
lines 7 - 8, Replace the direct system_auth role_members INSERT and
roles.member_of UPDATE in
migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql and
migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql with Cassandra’s
supported GRANT role-membership statement, granting each application access role
to its corresponding application role.

Source: MCP tools

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- Canonical schema for nvcf_autoscaler keyspace.
-- Pinned to the upstream nvcf_autoscaler schema at migration version 9.
-- account_id (TEXT) consolidates upstream nca_id_string from migrations 02-09. nca_id UUID dropped (NCA IDs are not UUIDs and the column was unused).
Comment on lines +1 to +3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Align the schema baseline and design record before publication.

The SQL comments describe a column-level schema change, while the design record promises that only replica-count templating changes. Resolve this contradiction by either restoring the archived schema or explicitly approving and documenting the compatibility impact.

  • migrations/cassandra/keyspaces/nvcf_autoscaler/03_init_tables.up.sql#L1-L3: restore the archived columns or document the approved field replacement and migration impact.
  • docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md#L37-L41: update the “only expression changes” compatibility claim.
  • docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md#L48-L49: update the verification requirement so it reflects the approved schema differences.
📍 Affects 2 files
  • migrations/cassandra/keyspaces/nvcf_autoscaler/03_init_tables.up.sql#L1-L3 (this comment)
  • docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md#L37-L41
  • docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md#L48-L49
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@migrations/cassandra/keyspaces/nvcf_autoscaler/03_init_tables.up.sql` around
lines 1 - 3, Resolve the schema/design inconsistency by either restoring the
archived columns in
migrations/cassandra/keyspaces/nvcf_autoscaler/03_init_tables.up.sql#L1-L3 or
documenting the approved account_id/nca_id replacement and migration impact.
Update
docs/superpowers/specs/2026-07-24-publish-cassandra-schemas-design.md#L37-L41 to
replace the “only expression changes” claim, and revise `#L48-L49` so verification
explicitly covers the approved schema differences.


-- ============================================================
-- Tables
-- ============================================================

-- Functions invoked recently. Rows expire via TTL to track a rolling window.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.recently_invoked_functions (
function_id UUID,
function_version_id UUID,
last_updated_at TIMESTAMP,
account_id TEXT,
PRIMARY KEY ((function_id, function_version_id))
) WITH default_time_to_live = 600
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';

-- Historical scaling decisions for recently invoked functions, clustered by time.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.recently_invoked_functions_history (
function_id UUID,
function_version_id UUID,
last_updated_at TIMESTAMP,
account_id TEXT STATIC,
num_workers INT STATIC,
last_predicted_desired_instance_count INT,
last_predicted_error_code TEXT,
PRIMARY KEY ((function_id, function_version_id), last_updated_at)
) WITH CLUSTERING ORDER BY (last_updated_at DESC)
AND default_time_to_live = 172800
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';

-- Functions with running workers but no recent invocations.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.running_functions_without_invocations (
function_id UUID,
function_version_id UUID,
last_updated_at TIMESTAMP,
account_id TEXT,
PRIMARY KEY ((function_id, function_version_id))
) WITH default_time_to_live = 600
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';

-- Historical scaling decisions for running functions without invocations, clustered by time.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.running_functions_without_invocations_history (
function_id UUID,
function_version_id UUID,
last_updated_at TIMESTAMP,
account_id TEXT STATIC,
num_workers INT STATIC,
last_predicted_desired_instance_count INT,
last_predicted_error_code TEXT,
PRIMARY KEY ((function_id, function_version_id), last_updated_at)
) WITH CLUSTERING ORDER BY (last_updated_at DESC)
AND default_time_to_live = 172800
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';

-- Distributed lock table for autoscaler leader coordination.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.locks (
lock_name TEXT PRIMARY KEY,
node_id TEXT,
acquired_at TIMESTAMP
) WITH default_time_to_live = 3600
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';

-- Liveness registry of autoscaler nodes. Rows expire quickly to reflect health.
CREATE TABLE IF NOT EXISTS nvcf_autoscaler.healthy_nodes (
node_id TEXT PRIMARY KEY,
last_updated_at TIMESTAMP
) WITH default_time_to_live = 180
AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'}
AND read_repair = 'NONE';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE KEYSPACE IF NOT EXISTS nvct_api WITH replication = {'class': 'NetworkTopologyStrategy', 'ncp': '${REPLICA_COUNT}' } AND durable_writes = true;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE ROLE IF NOT EXISTS nvct_api_app_access;
GRANT SELECT, MODIFY on keyspace nvct_api to nvct_api_app_access;
GRANT SELECT on keyspace system to nvct_api_app_access;

CREATE ROLE IF NOT EXISTS nvct_api_app_v0 with login = true and password = '${SERVICE_ROLE_PASSWORD}';

INSERT INTO system_auth.role_members (role, member) VALUES ('nvct_api_app_access', 'nvct_api_app_v0');
UPDATE system_auth.roles SET member_of = member_of + {'nvct_api_app_access'} where role = 'nvct_api_app_v0';
122 changes: 122 additions & 0 deletions migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
-- Canonical schema for nvct_api keyspace.
-- Reference: nvcf/nvct-api v1.2.4 local_env/cassandra/schema/0001_initial_schema.cql
Comment on lines +1 to +2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate guidance and relevant files
printf '\n== AGENTS files ==\n'
find .. -name AGENTS.md -print

printf '\n== Relevant file listings ==\n'
git ls-files 'migrations/cassandra/keyspaces/**' | sed -n '1,120p'

printf '\n== README pin references ==\n'
rg -n 'nvct_api|v1\.5\.2|v1\.2\.4|nvct-api' migrations/cassandra/keyspaces/README.md migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql || true

printf '\n== File sizes ==\n'
wc -l migrations/cassandra/keyspaces/README.md migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql

Repository: NVIDIA/nvcf

Length of output: 6104


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the small relevant sections with line numbers
printf '\n== README excerpt ==\n'
cat -n migrations/cassandra/keyspaces/README.md | sed -n '1,220p'

printf '\n== SQL excerpt ==\n'
cat -n migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql | sed -n '1,220p'

Repository: NVIDIA/nvcf

Length of output: 10620


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect nearby documentation for how the pinned source revisions are tracked.
rg -n 'v1\.5\.2|v1\.2\.4|nvct_api|schema/0001_initial_schema\.cql|design record|pin' migrations/cassandra/keyspaces -g '!**/*.png'

Repository: NVIDIA/nvcf

Length of output: 3684


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact README entry and any related design record references.
python3 - <<'PY'
from pathlib import Path
files = [
    Path('migrations/cassandra/keyspaces/README.md'),
    Path('migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql'),
]
for p in files:
    print(f"\n### {p} ###")
    text = p.read_text()
    for i, line in enumerate(text.splitlines(), 1):
        if 'nvct_api' in line or 'v1.5.2' in line or 'v1.2.4' in line or 'schema/0001_initial_schema.cql' in line:
            start = max(1, i-3)
            end = min(len(text.splitlines()), i+3)
            for j in range(start, end+1):
                print(f"{j}: {text.splitlines()[j-1]}")
            print()
PY

printf '\n== search for design record ==\n'
rg -n 'nvct_api|v1\.5\.2|v1\.2\.4|0001_initial_schema\.cql|design record|upstream schema' . -g '!**/.git/**'

Repository: NVIDIA/nvcf

Length of output: 20276


Update the provenance reference in migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql:2. The README pins nvct_api to v1.5.2, so the current v1.2.4 label is stale and makes the schema source unclear.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql` around lines 1
- 2, Update the provenance comment’s version reference for the nvct_api schema
from v1.2.4 to v1.5.2, keeping the existing source path and canonical-schema
wording unchanged.


-- ============================================================
-- User-Defined Types
-- ============================================================

CREATE TYPE IF NOT EXISTS nvct_api.model_udt (
name TEXT,
version TEXT,
url TEXT
);

CREATE TYPE IF NOT EXISTS nvct_api.resource_udt (
name TEXT,
version TEXT,
url TEXT
);

CREATE TYPE IF NOT EXISTS nvct_api.gpu_spec_udt (
instance_type TEXT,
gpu TEXT,
backend TEXT,
configuration TEXT,
clusters FROZEN<SET<TEXT>>,
regions FROZEN<SET<TEXT>>,
attributes FROZEN<SET<TEXT>>,
max_request_concurrency INT,
helm_validation_policy TEXT
);

CREATE TYPE IF NOT EXISTS nvct_api.health_udt (
sis_request_id UUID,
gpu TEXT,
backend TEXT,
instance_type TEXT,
error TEXT
);

CREATE TYPE IF NOT EXISTS nvct_api.telemetries_udt (
logs_telemetry_id UUID,
metrics_telemetry_id UUID,
traces_telemetry_id UUID
);

-- ============================================================
-- Tables
-- ============================================================

-- Primary task store. Each row is a unique task instance.
CREATE TABLE IF NOT EXISTS nvct_api.tasks_v2 (
nca_id TEXT,
task_id UUID,
name TEXT,
description TEXT,
tags FROZEN<SET<TEXT>>,
container_image TEXT,
container_args TEXT,
container_environment TEXT,
models FROZEN<SET<model_udt>>,
resources FROZEN<SET<resource_udt>>,
gpu_spec gpu_spec_udt,
max_runtime_duration DURATION,
max_queued_duration DURATION,
terminal_grace_period_duration DURATION,
result_handling_strategy TEXT,
helm_chart TEXT,
results_location TEXT,
status TEXT,
telemetries FROZEN<telemetries_udt>,
health_info FROZEN<health_udt>,
percent_complete INT,
last_updated_at TIMESTAMP,
last_heartbeat_at TIMESTAMP,
created_at TIMESTAMP,
has_secrets BOOLEAN,
PRIMARY KEY ((task_id))
);

CREATE CUSTOM INDEX IF NOT EXISTS tasks_v2_by_nca_id_sai_idx
ON nvct_api.tasks_v2 (nca_id) USING 'StorageAttachedIndex';

-- Tracks active SIS requests per task.
CREATE TABLE IF NOT EXISTS nvct_api.sis_requests_by_task (
task_id UUID,
sis_request_id UUID,
gpu_spec gpu_spec_udt,
total_request_size INT,
created_at TIMESTAMP,
PRIMARY KEY ((task_id), sis_request_id)
);

-- Events emitted during task lifecycle, keyed by task.
CREATE TABLE IF NOT EXISTS nvct_api.events_by_task (
task_id UUID,
event_id UUID,
nca_id TEXT,
message TEXT,
created_at TIMESTAMP,
PRIMARY KEY ((task_id), event_id)
);

-- Results produced by a task, keyed by task.
CREATE TABLE IF NOT EXISTS nvct_api.results_by_task (
task_id UUID,
result_id UUID,
nca_id TEXT,
name TEXT,
metadata TEXT,
created_at TIMESTAMP,
PRIMARY KEY ((task_id), result_id)
);

-- Distributed lock table for scheduled background tasks.
-- Primary key must be 'name'.
CREATE TABLE IF NOT EXISTS nvct_api.lock (
name TEXT,
lockuntil TIMESTAMP,
lockedat TIMESTAMP,
lockedby TEXT,
PRIMARY KEY ((name))
);
18 changes: 18 additions & 0 deletions migrations/cassandra/tests/test-execute-sqls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ fail()
status=1
}

schema_inventory=$(
# shellcheck disable=SC2016
sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \
"${keyspaces}/README.md"
)
for keyspace_name in ${schema_inventory}; do
Comment on lines +19 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail closed when the schema inventory is empty.

If the README format changes or parsing returns no rows, the loop is skipped and CI reports success without checking any schema. Add an assertion before the loop:

Proposed fix
 schema_inventory=$(
   sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \
     "${keyspaces}/README.md"
 )
+if [ -z "${schema_inventory}" ]; then
+  fail "schema inventory is empty or malformed"
+fi
 for keyspace_name in ${schema_inventory}; do
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
schema_inventory=$(
# shellcheck disable=SC2016
sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \
"${keyspaces}/README.md"
)
for keyspace_name in ${schema_inventory}; do
schema_inventory=$(
# shellcheck disable=SC2016
sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \
"${keyspaces}/README.md"
)
if [ -z "${schema_inventory}" ]; then
fail "schema inventory is empty or malformed"
fi
for keyspace_name in ${schema_inventory}; do
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@migrations/cassandra/tests/test-execute-sqls.sh` around lines 19 - 24,
Validate that schema_inventory produced by the README parsing command is
non-empty before entering the keyspace_name loop. If no schema names were
parsed, exit with a failure status and a clear diagnostic; otherwise preserve
the existing loop behavior.

for migration_name in \
01_init_keyspace.up.sql \
02_init_roles.up.sql \
03_init_tables.up.sql
do
migration="${keyspaces}/${keyspace_name}/${migration_name}"
if [ ! -f "${migration}" ]; then
fail "schema inventory entry ${keyspace_name} is missing ${migration_name}"
fi
done
done

if grep -R -n -F 'envOrDefault "REPLICA_COUNT"' "${keyspaces}"; then
fail "keyspace migrations contain templates unsupported by stock golang-migrate"
fi
Expand Down
Loading