@runa-ai/runa-cli 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'module';
3
3
  import { detectDatabaseStack, getStackPaths } from './chunk-MILCC3B6.js';
4
4
  import { categorizeRisks, detectSchemaRisks } from './chunk-XFXGFUAM.js';
5
- import { isExecaError, resolveDbPreviewEnvironment, buildDbPlanCommandLabel, runDbApply, buildDbApplyCliError, DbPlanOutputSchema, parseDbPreviewProfile, DEFAULT_DB_PREVIEW_PROFILE, getDbPreviewModeLabel, buildDbPreviewCommandLabel, isCompareOnlyPreviewProfile, DbApplyOutputSchema, applyCommand, getDbPreviewIdempotentSchemaCount, classifyDbSyncCommandFailure, getDbSyncFallbackSuggestions, detectAppSchemas, normalizeDatabaseUrlForDdl, analyzeDuplicateFunctionOwnership, formatDuplicateFunctionOwnershipFinding, reviewDeclarativeDependencyWarnings, logDeclarativeDependencyWarnings, buildDeclarativeDependencyWarningFailureLines, parsePlanOutput, validateDependencyOrder, getBoundaryPolicy, resolveProductionApplyStrictMode, findDeclarativeRiskAllowlistMatch, assertBoundaryPolicyUsable, assertBoundaryPolicyQualityGate, formatSchemasForSql, findDirectoryPlacementAllowlistMatch, formatAllowlistMetadata, assessPlanSize, formatPlanSizeSummary, extractFunctionOwnershipDefinition } from './chunk-LCJNIHZY.js';
5
+ import { isExecaError, resolveDbPreviewEnvironment, buildDbPlanCommandLabel, runDbApply, buildDbApplyCliError, DbPlanOutputSchema, parseDbPreviewProfile, DEFAULT_DB_PREVIEW_PROFILE, getDbPreviewModeLabel, buildDbPreviewCommandLabel, isCompareOnlyPreviewProfile, DbApplyOutputSchema, applyCommand, getDbPreviewIdempotentSchemaCount, classifyDbSyncCommandFailure, getDbSyncFallbackSuggestions, detectAppSchemas, normalizeDatabaseUrlForDdl, analyzeDuplicateFunctionOwnership, formatDuplicateFunctionOwnershipFinding, reviewDeclarativeDependencyWarnings, logDeclarativeDependencyWarnings, buildDeclarativeDependencyWarningFailureLines, parsePlanOutput, validateDependencyOrder, getBoundaryPolicy, resolveProductionApplyStrictMode, findDeclarativeRiskAllowlistMatch, assertBoundaryPolicyUsable, assertBoundaryPolicyQualityGate, formatSchemasForSql, findDirectoryPlacementAllowlistMatch, formatAllowlistMetadata, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH, functionAclManifestHasEntries, validateFunctionAclMigration, isManagedFunctionAclFileContentStale, renderFunctionAclFile, assessPlanSize, formatPlanSizeSummary, buildFunctionAclManifestFromSqlFiles, buildFunctionAclIdempotentTouchMetadata, stableSorted, normalizePolicyCommand, normalizeFileList, extractFunctionOwnershipDefinition, SECURITY_DEFINER_RE, MANAGED_BOUNDARY_SCHEMAS, currentIsoTimestamp, makeGraphVersion, GENERATOR_VERSION, MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE, QUALIFIED_SQL_OBJECT_RE, SEARCH_PATH_LOCK_RE, TRIGGER_GUIDANCE_SUPPRESSED_FUNCTIONS, SQL_EXTENSION_IDENTIFIER_PATTERN, SQL_IDENTIFIER_PATTERN } from './chunk-S7VGVFYF.js';
6
6
  import { createError } from './chunk-NIS77243.js';
7
7
  import { resolveDatabaseUrl, resolveDatabaseTarget, tryResolveDatabaseUrl } from './chunk-WGRVAGSR.js';
8
8
  export { resolveDatabaseUrl, tryResolveDatabaseUrl } from './chunk-WGRVAGSR.js';
@@ -10,7 +10,7 @@ import { analyzeDeclarativeDependencyContract, formatDeclarativeDependencyViolat
10
10
  import './chunk-UHDAYPHH.js';
11
11
  import './chunk-EZ46JIEO.js';
12
12
  import { loadEnvFiles } from './chunk-IWVXI5O4.js';
13
- import './chunk-IR7SA2ME.js';
13
+ import './chunk-SS7RIWW3.js';
14
14
  import { diagnoseSupabaseStart } from './chunk-AAIE4F2U.js';
15
15
  import { validateUserFilePath, filterSafePaths, resolveSafePath } from './chunk-B7C7CLW2.js';
16
16
  import { runMachine } from './chunk-QDF7QXBL.js';
@@ -1145,7 +1145,8 @@ z.object({
1145
1145
  });
1146
1146
  var SchemaManagedBlockKindSchema = z.enum([
1147
1147
  "file-header",
1148
- "table-header"
1148
+ "table-header",
1149
+ "generated-file"
1149
1150
  ]);
1150
1151
  var SchemaGuardrailPhaseIdSchema = z.enum([
1151
1152
  "load_sources",
@@ -1166,6 +1167,7 @@ var SchemaGuardrailFailureCodeSchema = z.enum([
1166
1167
  "dynamic_sql_blocked",
1167
1168
  "extension_placement_blocked",
1168
1169
  "stale_generated_header",
1170
+ "function_acl_migration_required",
1169
1171
  "generated_header_validation_failed",
1170
1172
  "generated_header_rewrite_failed",
1171
1173
  "static_graph_build_failed",
@@ -1509,39 +1511,46 @@ function buildGuardrailConflictEntries(report, entries) {
1509
1511
  pushSemanticEvidenceEntries(entries, report);
1510
1512
  pushBoundaryGuidanceEntries(entries, report);
1511
1513
  }
1512
- function buildGuardrailHeaderEntries(report, entries) {
1513
- if (report.staleBlocks.length > 0) {
1514
- const byFile = /* @__PURE__ */ new Map();
1515
- for (const block of report.staleBlocks) {
1516
- const kinds = byFile.get(block.file) ?? [];
1517
- kinds.push(block.kind === "file-header" ? "file metadata" : `table: ${block.target}`);
1518
- byFile.set(block.file, kinds);
1519
- }
1514
+ function describeStaleBlock(block) {
1515
+ return block.kind === "file-header" ? "file metadata" : block.kind === "generated-file" ? "managed file body" : `table: ${block.target}`;
1516
+ }
1517
+ function pushStaleArtifactEntries(report, entries) {
1518
+ if (report.staleBlocks.length === 0) {
1519
+ return;
1520
+ }
1521
+ const byFile = /* @__PURE__ */ new Map();
1522
+ for (const block of report.staleBlocks) {
1523
+ const kinds = byFile.get(block.file) ?? [];
1524
+ kinds.push(describeStaleBlock(block));
1525
+ byFile.set(block.file, kinds);
1526
+ }
1527
+ entries.push({
1528
+ level: "warn",
1529
+ message: `Generated SQL artifacts are stale (${report.staleBlocks.length} block(s) in ${byFile.size} file(s)):`
1530
+ });
1531
+ for (const [file, kinds] of byFile) {
1520
1532
  entries.push({
1521
- level: "warn",
1522
- message: `Generated headers are stale (${report.staleBlocks.length} block(s) in ${byFile.size} file(s)):`
1533
+ level: "info",
1534
+ message: ` ${file}: ${kinds.join(", ")}`
1535
+ });
1536
+ }
1537
+ if (!report.failure) {
1538
+ entries.push({
1539
+ level: "info",
1540
+ message: "Auto-fix: Run `runa db sync` to regenerate managed SQL artifacts automatically."
1541
+ });
1542
+ entries.push({
1543
+ level: "info",
1544
+ message: "Managed SQL artifacts track: FK references, RLS policies, triggers, function ownership, schema dependencies, and function ACL reconciliation."
1523
1545
  });
1524
- for (const [file, kinds] of byFile) {
1525
- entries.push({
1526
- level: "info",
1527
- message: ` ${file}: ${kinds.join(", ")}`
1528
- });
1529
- }
1530
- if (!report.failure) {
1531
- entries.push({
1532
- level: "info",
1533
- message: "Auto-fix: Run `runa db sync` to regenerate all headers automatically."
1534
- });
1535
- entries.push({
1536
- level: "info",
1537
- message: "Headers track: FK references, RLS policies, triggers, function ownership, and schema dependencies."
1538
- });
1539
- }
1540
1546
  }
1547
+ }
1548
+ function buildGuardrailHeaderEntries(report, entries) {
1549
+ pushStaleArtifactEntries(report, entries);
1541
1550
  if (report.headersRewritten.length > 0) {
1542
1551
  entries.push({
1543
1552
  level: "info",
1544
- message: `Generated headers refreshed in ${report.headersRewritten.length} file(s).`
1553
+ message: `Generated SQL artifacts refreshed in ${report.headersRewritten.length} file(s).`
1545
1554
  });
1546
1555
  }
1547
1556
  }
@@ -2797,7 +2806,7 @@ function normalizeAllowlistSignature(value) {
2797
2806
  function normalizeSuppressionPair(value) {
2798
2807
  return value.split("::").map((part) => part.trim().toLowerCase()).filter((part) => part.length > 0).sort((left, right) => left.localeCompare(right)).join("::");
2799
2808
  }
2800
- function normalizeFileList(files) {
2809
+ function normalizeFileList2(files) {
2801
2810
  return [...new Set(files)].sort((a, b) => a.localeCompare(b));
2802
2811
  }
2803
2812
  function isSchemaGuardrailTextFallbackAllowed() {
@@ -2859,7 +2868,7 @@ function loadSchemaGuardrailConfig(targetDir) {
2859
2868
  // Fallback: merge schema-ownership.json allowed_duplicates if present
2860
2869
  ...loadAllowedDuplicatesFromSchemaOwnership(targetDir)
2861
2870
  ],
2862
- generatedHeaderRewriteTargets: normalizeFileList(
2871
+ generatedHeaderRewriteTargets: normalizeFileList2(
2863
2872
  (databaseConfig.schemaGuardrails?.generatedHeaderRewriteTargets ?? []).map(
2864
2873
  (value) => normalizePathForMatch(value)
2865
2874
  )
@@ -2884,7 +2893,7 @@ function loadSchemaGuardrailConfig(targetDir) {
2884
2893
  defaults,
2885
2894
  normalizers: {
2886
2895
  normalizeAllowlistSignature,
2887
- normalizeFileList,
2896
+ normalizeFileList: normalizeFileList2,
2888
2897
  normalizeFunctionQualifiedName,
2889
2898
  normalizePathForMatch,
2890
2899
  normalizeSuppressionPair
@@ -5441,7 +5450,7 @@ init_esm_shims();
5441
5450
 
5442
5451
  // src/commands/db/sync/schema-guardrail-runtime.ts
5443
5452
  init_esm_shims();
5444
- function stableSorted(values, map) {
5453
+ function stableSorted2(values, map) {
5445
5454
  return [...values].sort((a, b) => map(a).localeCompare(map(b)));
5446
5455
  }
5447
5456
  function normalizeFkSet(foreignKeys) {
@@ -5563,8 +5572,8 @@ function reconcileRuntimeGraph(params) {
5563
5572
  });
5564
5573
  }
5565
5574
  return {
5566
- warnings: stableSorted(warnings, (value) => value.target),
5567
- contradictions: stableSorted(contradictions, (value) => `${value.code}.${value.target}`)
5575
+ warnings: stableSorted2(warnings, (value) => value.target),
5576
+ contradictions: stableSorted2(contradictions, (value) => `${value.code}.${value.target}`)
5568
5577
  };
5569
5578
  }
5570
5579
  function runSchemaGuardrailRuntime(input) {
@@ -5594,7 +5603,7 @@ function runSchemaGuardrailRuntime(input) {
5594
5603
 
5595
5604
  // src/commands/db/sync/schema-guardrail-local-blockers.ts
5596
5605
  init_esm_shims();
5597
- function stableSorted2(values, keyOf) {
5606
+ function stableSorted3(values, keyOf) {
5598
5607
  return [...values].sort((left, right) => keyOf(left).localeCompare(keyOf(right)));
5599
5608
  }
5600
5609
  function createCrossSchemaHelperSuggestion(_filePath) {
@@ -5623,7 +5632,7 @@ function buildRawCrossSchemaRlsBlockers(params) {
5623
5632
  });
5624
5633
  }
5625
5634
  }
5626
- return stableSorted2(
5635
+ return stableSorted3(
5627
5636
  blockers,
5628
5637
  (value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
5629
5638
  );
@@ -5650,7 +5659,7 @@ function buildExtensionPlacementBlockers(params) {
5650
5659
  });
5651
5660
  }
5652
5661
  }
5653
- return stableSorted2(
5662
+ return stableSorted3(
5654
5663
  blockers,
5655
5664
  (value) => `${value.sourceFile}:${value.line ?? 0}:${value.target}`
5656
5665
  );
@@ -5741,7 +5750,7 @@ function buildDynamicSqlBlockers(params) {
5741
5750
  blockers.push(...stmtBlockers);
5742
5751
  }
5743
5752
  }
5744
- return stableSorted2(blockers, (value) => `${value.sourceFile}:${value.line ?? 0}:${value.kind}`);
5753
+ return stableSorted3(blockers, (value) => `${value.sourceFile}:${value.line ?? 0}:${value.kind}`);
5745
5754
  }
5746
5755
  function buildLocalBlindSpotBlockers(params) {
5747
5756
  const blockers = [
@@ -5758,7 +5767,7 @@ function buildLocalBlindSpotBlockers(params) {
5758
5767
  requiredFile: detectExtensionFilePath()
5759
5768
  })
5760
5769
  ];
5761
- return stableSorted2(
5770
+ return stableSorted3(
5762
5771
  blockers,
5763
5772
  (value) => `${value.kind}:${value.sourceFile}:${value.line ?? 0}:${value.target}`
5764
5773
  );
@@ -5766,7 +5775,7 @@ function buildLocalBlindSpotBlockers(params) {
5766
5775
 
5767
5776
  // src/commands/db/sync/schema-guardrail-semantic-warnings.ts
5768
5777
  init_esm_shims();
5769
- function stableSorted3(values, map) {
5778
+ function stableSorted4(values, map) {
5770
5779
  return [...values].sort((a, b) => map(a).localeCompare(map(b)));
5771
5780
  }
5772
5781
  function normalizeFkSet2(foreignKeys) {
@@ -5971,50 +5980,7 @@ function buildSemanticDuplicateWarnings(params) {
5971
5980
  suppressionKey: createSuppressionPair(proposed.qualifiedName, primary.qualifiedName)
5972
5981
  });
5973
5982
  }
5974
- return stableSorted3(warnings, (value) => `${value.proposedTable}.${value.suppressionKey}`);
5975
- }
5976
-
5977
- // src/commands/db/sync/schema-guardrail-graph-types.ts
5978
- init_esm_shims();
5979
- var GENERATOR_VERSION = "1.0.0";
5980
- var SQL_IDENTIFIER_PATTERN = /"(?:[^"]|"")+"|[A-Za-z_][A-Za-z0-9_$]*/g;
5981
- var SQL_EXTENSION_IDENTIFIER_PATTERN = /"(?:[^"]|"")+"|[A-Za-z0-9_-]+/g;
5982
- var QUALIFIED_SQL_OBJECT_RE = /\b([A-Za-z_][A-Za-z0-9_$]*)\s*\.\s*([A-Za-z_][A-Za-z0-9_$]*)\b/g;
5983
- var SECURITY_DEFINER_RE = /\bSECURITY\s+DEFINER\b/i;
5984
- var SEARCH_PATH_LOCK_RE = /\bSET\s+search_path\s*(?:=|TO)\s*''/i;
5985
- var MANAGED_BOUNDARY_SCHEMAS = [
5986
- "auth",
5987
- "storage",
5988
- "extensions",
5989
- "net",
5990
- "supabase_functions"
5991
- ];
5992
- var TRIGGER_GUIDANCE_SUPPRESSED_FUNCTIONS = /* @__PURE__ */ new Set(["public.handle_updated_at()"]);
5993
- var MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE = 3;
5994
- function makeGraphVersion(graph) {
5995
- const canonical = JSON.stringify(graph);
5996
- const hash = createHash("sha256").update(canonical).digest("hex");
5997
- return `sha256:${hash}`;
5998
- }
5999
- function currentIsoTimestamp() {
6000
- return (/* @__PURE__ */ new Date()).toISOString();
6001
- }
6002
- function stableSorted4(values, map) {
6003
- return [...values].sort((a, b) => map(a).localeCompare(map(b)));
6004
- }
6005
- function normalizeFileList2(files) {
6006
- return [...new Set(files)].sort((a, b) => a.localeCompare(b));
6007
- }
6008
- function normalizePolicyCommand(input) {
6009
- switch (input.toLowerCase()) {
6010
- case "select":
6011
- case "insert":
6012
- case "update":
6013
- case "delete":
6014
- return input.toLowerCase();
6015
- default:
6016
- return "all";
6017
- }
5983
+ return stableSorted4(warnings, (value) => `${value.proposedTable}.${value.suppressionKey}`);
6018
5984
  }
6019
5985
 
6020
5986
  // src/commands/db/sync/schema-guardrail-graph-nodes.ts
@@ -6060,8 +6026,8 @@ function collectQualifiedObjectRefs(params) {
6060
6026
  schemas.add(schema);
6061
6027
  }
6062
6028
  return {
6063
- refs: stableSorted4(refs, (value) => value),
6064
- schemas: stableSorted4(schemas, (value) => value)
6029
+ refs: stableSorted(refs, (value) => value),
6030
+ schemas: stableSorted(schemas, (value) => value)
6065
6031
  };
6066
6032
  }
6067
6033
  function isSearchPathLocked(statement) {
@@ -6099,7 +6065,7 @@ function buildDefinedFunctionMetadataByFile(params) {
6099
6065
  }
6100
6066
  metadataByFile.set(
6101
6067
  file.relativePath,
6102
- stableSorted4(fileMetadata, (value) => value.qualifiedSignature)
6068
+ stableSorted(fileMetadata, (value) => value.qualifiedSignature)
6103
6069
  );
6104
6070
  }
6105
6071
  return metadataByFile;
@@ -6193,13 +6159,13 @@ async function buildDeclarativeFileRecord(file) {
6193
6159
  file,
6194
6160
  declaredSchemas: [...declaredSchemas].sort((a, b) => a.localeCompare(b)),
6195
6161
  createSchemaClaims: [...createSchemaClaims].sort((a, b) => a.localeCompare(b)),
6196
- tables: stableSorted4(
6162
+ tables: stableSorted(
6197
6163
  document.tables.map((table) => ({
6198
6164
  schema: table.schema,
6199
6165
  name: table.name,
6200
6166
  qualifiedName: table.qualifiedName,
6201
6167
  lineNumber: table.lineNumber,
6202
- columns: stableSorted4(table.columns, (value) => value.name).map((value) => value.name),
6168
+ columns: stableSorted(table.columns, (value) => value.name).map((value) => value.name),
6203
6169
  outboundForeignKeys: table.foreignKeys.map((fk) => ({
6204
6170
  column: fk.column,
6205
6171
  referencesTable: fk.referencesTable,
@@ -6210,7 +6176,7 @@ async function buildDeclarativeFileRecord(file) {
6210
6176
  })),
6211
6177
  (value) => value.qualifiedName
6212
6178
  ),
6213
- policies: stableSorted4(
6179
+ policies: stableSorted(
6214
6180
  document.policies.map((policy) => ({
6215
6181
  name: policy.name,
6216
6182
  targetTable: `${policy.schema}.${policy.table}`,
@@ -6264,10 +6230,10 @@ function collectDeclarativeClaims(records) {
6264
6230
  };
6265
6231
  }
6266
6232
  function createDuplicateTableOwners(tableOwnerClaims) {
6267
- return stableSorted4(
6233
+ return stableSorted(
6268
6234
  [...tableOwnerClaims.entries()].filter(([, files]) => files.size > 1).map(([qualifiedName, files]) => ({
6269
6235
  qualifiedName,
6270
- files: normalizeFileList2(files)
6236
+ files: normalizeFileList(files)
6271
6237
  })),
6272
6238
  (value) => value.qualifiedName
6273
6239
  );
@@ -6281,7 +6247,7 @@ function buildFunctionValidationArtifacts(params) {
6281
6247
  ...buildFunctionBodyHashMap(params.declarativeFiles, "declarative"),
6282
6248
  ...buildFunctionBodyHashMap(params.idempotentFiles, "idempotent")
6283
6249
  ]);
6284
- const duplicateFunctionOwners = stableSorted4(
6250
+ const duplicateFunctionOwners = stableSorted(
6285
6251
  functionAnalysis.findings.filter(
6286
6252
  (finding) => !isAllowlistedDuplicateFunction({
6287
6253
  finding,
@@ -6291,16 +6257,16 @@ function buildFunctionValidationArtifacts(params) {
6291
6257
  ).map((finding) => ({
6292
6258
  qualifiedName: finding.qualifiedName,
6293
6259
  signature: finding.signature,
6294
- declarativeFiles: normalizeFileList2(
6260
+ declarativeFiles: normalizeFileList(
6295
6261
  finding.declarativeDefinitions.map((value) => value.file)
6296
6262
  ),
6297
- idempotentFiles: normalizeFileList2(
6263
+ idempotentFiles: normalizeFileList(
6298
6264
  finding.idempotentDefinitions.map((value) => value.file)
6299
6265
  )
6300
6266
  })),
6301
6267
  (value) => `${value.qualifiedName}.${value.signature ?? ""}`
6302
6268
  );
6303
- const functionClaims = stableSorted4(
6269
+ const functionClaims = stableSorted(
6304
6270
  [
6305
6271
  ...functionAnalysis.definitions.declarative.map((definition) => ({
6306
6272
  qualifiedName: definition.qualifiedName,
@@ -6329,7 +6295,7 @@ function buildFunctionValidationArtifacts(params) {
6329
6295
  function buildOwnerFileByTable(tableOwnerClaims) {
6330
6296
  const ownerFileByTable = /* @__PURE__ */ new Map();
6331
6297
  for (const [qualifiedName, files] of tableOwnerClaims.entries()) {
6332
- const normalizedFiles = normalizeFileList2(files);
6298
+ const normalizedFiles = normalizeFileList(files);
6333
6299
  if (normalizedFiles[0]) {
6334
6300
  ownerFileByTable.set(qualifiedName, normalizedFiles[0]);
6335
6301
  }
@@ -6349,7 +6315,7 @@ function buildPolicyOwnershipConflicts(params) {
6349
6315
  conflicts.push({
6350
6316
  policyName: policyClaim.name,
6351
6317
  targetTable: policyClaim.targetTable,
6352
- files: normalizeFileList2([policyClaim.sourceFile]),
6318
+ files: normalizeFileList([policyClaim.sourceFile]),
6353
6319
  tableOwnerFile: ownerFile
6354
6320
  });
6355
6321
  }
@@ -6360,11 +6326,11 @@ function buildPolicyOwnershipConflicts(params) {
6360
6326
  conflicts.push({
6361
6327
  policyName,
6362
6328
  targetTable,
6363
- files: normalizeFileList2(files),
6329
+ files: normalizeFileList(files),
6364
6330
  tableOwnerFile: params.ownerFileByTable.get(targetTable) ?? ""
6365
6331
  });
6366
6332
  }
6367
- return stableSorted4(
6333
+ return stableSorted(
6368
6334
  conflicts,
6369
6335
  (value) => `${value.targetTable}.${value.policyName}.${value.files.join(",")}`
6370
6336
  );
@@ -6380,16 +6346,16 @@ function buildTableNodesByName(params) {
6380
6346
  ownerFile: record.file.relativePath,
6381
6347
  lineNumber: table.lineNumber,
6382
6348
  columns: table.columns,
6383
- outboundForeignKeys: stableSorted4(
6349
+ outboundForeignKeys: stableSorted(
6384
6350
  table.outboundForeignKeys,
6385
6351
  (value) => `${value.referencesTable}.${value.column}`
6386
6352
  ),
6387
6353
  inboundForeignKeys: [],
6388
- policies: stableSorted4(
6354
+ policies: stableSorted(
6389
6355
  params.tablePolicies.get(table.qualifiedName) ?? [],
6390
6356
  (value) => value.name
6391
6357
  ),
6392
- triggers: stableSorted4(
6358
+ triggers: stableSorted(
6393
6359
  record.triggersByTable.get(table.qualifiedName) ?? [],
6394
6360
  (value) => value.name
6395
6361
  )
@@ -6413,7 +6379,7 @@ function attachInboundForeignKeys(tableNodesByName) {
6413
6379
  }
6414
6380
  }
6415
6381
  for (const tableNode of tableNodesByName.values()) {
6416
- tableNode.inboundForeignKeys = stableSorted4(
6382
+ tableNode.inboundForeignKeys = stableSorted(
6417
6383
  tableNode.inboundForeignKeys,
6418
6384
  (value) => `${value.fromTable}.${value.fromColumn}`
6419
6385
  );
@@ -6432,12 +6398,12 @@ function buildFileDependencies(params) {
6432
6398
  fileDependencyMap.set(tableNode.ownerFile, edges);
6433
6399
  }
6434
6400
  }
6435
- return stableSorted4(
6401
+ return stableSorted(
6436
6402
  [...fileDependencyMap.entries()].flatMap(
6437
6403
  ([fromFile, toMap]) => [...toMap.entries()].map(([toFile, viaTables]) => ({
6438
6404
  fromFile,
6439
6405
  toFile,
6440
- viaTables: normalizeFileList2(viaTables)
6406
+ viaTables: normalizeFileList(viaTables)
6441
6407
  }))
6442
6408
  ),
6443
6409
  (value) => `${value.fromFile}->${value.toFile}`
@@ -6459,7 +6425,7 @@ function buildFileNodes(params) {
6459
6425
  ["22_observability_cron.sql", "cron-registration"],
6460
6426
  ["25_storage_seed_bucket.sql", "storage-bootstrap"]
6461
6427
  ]);
6462
- return stableSorted4(
6428
+ return stableSorted(
6463
6429
  [
6464
6430
  ...params.records.map((record) => {
6465
6431
  const definedFunctions = params.definedFunctionMetadataByFile.get(record.file.relativePath) ?? [];
@@ -6469,7 +6435,7 @@ function buildFileNodes(params) {
6469
6435
  schemas: [],
6470
6436
  refs: []
6471
6437
  };
6472
- const triggerFunctions = stableSorted4(
6438
+ const triggerFunctions = stableSorted(
6473
6439
  new Set(
6474
6440
  [...record.triggersByTable.values()].flat().map((trigger) => normalizeTriggerFunctionToken(trigger.functionName)).filter((value) => value !== null)
6475
6441
  ),
@@ -6482,7 +6448,7 @@ function buildFileNodes(params) {
6482
6448
  domainName: path12.basename(record.file.relativePath, ".sql"),
6483
6449
  declaredSchemas: record.declaredSchemas,
6484
6450
  ownedTables: record.tables.map((table) => table.qualifiedName),
6485
- forwardDependsOnFiles: stableSorted4(
6451
+ forwardDependsOnFiles: stableSorted(
6486
6452
  params.fileDependencies.filter((edge) => edge.fromFile === record.file.relativePath).map((edge) => edge.toFile),
6487
6453
  (value) => value
6488
6454
  ),
@@ -6490,7 +6456,7 @@ function buildFileNodes(params) {
6490
6456
  securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
6491
6457
  securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
6492
6458
  triggerFunctions,
6493
- functionCrossSchemaRefs: stableSorted4(
6459
+ functionCrossSchemaRefs: stableSorted(
6494
6460
  new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
6495
6461
  (value) => value
6496
6462
  ),
@@ -6500,7 +6466,7 @@ function buildFileNodes(params) {
6500
6466
  touchedExtensions: [],
6501
6467
  touchedFunctions: [],
6502
6468
  touchedPolicies: [],
6503
- policyCrossSchemaRefs: stableSorted4(
6469
+ policyCrossSchemaRefs: stableSorted(
6504
6470
  new Set(
6505
6471
  collectPolicyCrossSchemaReferences({
6506
6472
  content: record.file.content,
@@ -6537,7 +6503,7 @@ function buildFileNodes(params) {
6537
6503
  securityDefinerFunctions: definedFunctions.filter((value) => value.securityDefiner).map((value) => value.qualifiedSignature),
6538
6504
  securityDefinerContracts: definedFunctions.filter((value) => value.securityDefiner && value.searchPathLocked).map((value) => value.qualifiedSignature),
6539
6505
  triggerFunctions: [],
6540
- functionCrossSchemaRefs: stableSorted4(
6506
+ functionCrossSchemaRefs: stableSorted(
6541
6507
  new Set(definedFunctions.flatMap((value) => value.crossSchemaRefs)),
6542
6508
  (value) => value
6543
6509
  ),
@@ -6700,7 +6666,7 @@ function extractTouchedSchemas(content) {
6700
6666
  }
6701
6667
  }
6702
6668
  }
6703
- return stableSorted4(touched, (value) => value);
6669
+ return stableSorted(touched, (value) => value);
6704
6670
  }
6705
6671
  function extractTouchedFunctions(content) {
6706
6672
  const touched = /* @__PURE__ */ new Set();
@@ -6717,7 +6683,7 @@ function extractTouchedFunctions(content) {
6717
6683
  }
6718
6684
  }
6719
6685
  }
6720
- return stableSorted4(touched, (value) => value);
6686
+ return stableSorted(touched, (value) => value);
6721
6687
  }
6722
6688
  function normalizeExtensionIdentifier(identifier) {
6723
6689
  const trimmed = identifier.trim();
@@ -6740,7 +6706,7 @@ function extractTouchedExtensions(content) {
6740
6706
  }
6741
6707
  touched.add(normalizeExtensionIdentifier(identifier));
6742
6708
  }
6743
- return stableSorted4(touched, (value) => value);
6709
+ return stableSorted(touched, (value) => value);
6744
6710
  }
6745
6711
  function extractTouchedPolicies(content) {
6746
6712
  const touched = /* @__PURE__ */ new Set();
@@ -6754,7 +6720,7 @@ function extractTouchedPolicies(content) {
6754
6720
  }
6755
6721
  touched.add(`${schemaName}.${tableName}.${policyName}`);
6756
6722
  }
6757
- return stableSorted4(touched, (value) => value);
6723
+ return stableSorted(touched, (value) => value);
6758
6724
  }
6759
6725
  function extractIdempotentTouchMetadata(file) {
6760
6726
  const sanitizedContent = sanitizeIdempotentTouchScanContent(file.content);
@@ -6772,7 +6738,7 @@ function buildIdempotentTouchMetadata(files) {
6772
6738
  // src/commands/db/sync/schema-guardrail-graph-guidance.ts
6773
6739
  init_esm_shims();
6774
6740
  function summarizeBoundaryTargets(targets) {
6775
- const sortedTargets = stableSorted4(new Set(targets), (value) => value);
6741
+ const sortedTargets = stableSorted(new Set(targets), (value) => value);
6776
6742
  if (sortedTargets.length <= 2) {
6777
6743
  return sortedTargets.join(", ");
6778
6744
  }
@@ -6925,7 +6891,7 @@ function buildUnlockedSecurityDefinerGuidanceWarnings(params) {
6925
6891
  return [];
6926
6892
  }
6927
6893
  const lockedContracts = new Set(params.fileNode.securityDefinerContracts);
6928
- const unlockedFunctions = stableSorted4(
6894
+ const unlockedFunctions = stableSorted(
6929
6895
  params.fileNode.securityDefinerFunctions.filter(
6930
6896
  (qualifiedName) => !lockedContracts.has(qualifiedName)
6931
6897
  ),
@@ -6989,7 +6955,7 @@ function buildSecurityDefinerGuidanceWarnings(params) {
6989
6955
  if (!suggestedIdempotentFile || !targets) {
6990
6956
  return [];
6991
6957
  }
6992
- const touchedSecurityDefiners = stableSorted4(
6958
+ const touchedSecurityDefiners = stableSorted(
6993
6959
  new Set(targets.filter((target) => securityDefinerSet.has(target))),
6994
6960
  (value) => value
6995
6961
  );
@@ -7077,7 +7043,7 @@ function buildBoundaryGuidanceWarnings(params) {
7077
7043
  );
7078
7044
  continue;
7079
7045
  }
7080
- const touchedSchemas = stableSorted4(new Set(fileNode.touchedSchemas), (value) => value);
7046
+ const touchedSchemas = stableSorted(new Set(fileNode.touchedSchemas), (value) => value);
7081
7047
  if (touchedSchemas.length <= MAX_SCHEMA_GUIDANCE_TARGETS_PER_FILE) {
7082
7048
  for (const schema of touchedSchemas) {
7083
7049
  const ownerFile = schemaOwnerByName.get(schema);
@@ -7114,7 +7080,7 @@ function buildBoundaryGuidanceWarnings(params) {
7114
7080
  reason: "This idempotent file applies policy DDL against a table that is structurally owned in declarative SQL."
7115
7081
  });
7116
7082
  }
7117
- return stableSorted4(
7083
+ return stableSorted(
7118
7084
  warnings,
7119
7085
  (value) => `${value.sourceFile}.${value.kind}.${value.suggestedDeclarativeFile ?? ""}.${value.suggestedIdempotentFile ?? ""}.${value.target}`
7120
7086
  );
@@ -7190,7 +7156,7 @@ function validateDispatchCoverage(argsByFunction, sources) {
7190
7156
  }
7191
7157
  }
7192
7158
  }
7193
- return stableSorted4(warnings, (w) => `${w.sourceFile}:${w.target}`);
7159
+ return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
7194
7160
  }
7195
7161
  var CREATE_INDEX_PATTERN = /^\s*CREATE\s+(?:UNIQUE\s+)?(?:INDEX\s+)?(?:CONCURRENTLY\s+)?(?:IF\s+NOT\s+EXISTS\s+)?(?:"([^"]+)"|([A-Za-z_]\w*))\s+ON\b/gim;
7196
7162
  function extractIndexNames(content) {
@@ -7225,7 +7191,7 @@ function buildCrossLayerDuplicateIndexWarnings(sources) {
7225
7191
  }
7226
7192
  }
7227
7193
  }
7228
- return stableSorted4(warnings, (w) => `${w.sourceFile}:${w.target}`);
7194
+ return stableSorted(warnings, (w) => `${w.sourceFile}:${w.target}`);
7229
7195
  }
7230
7196
 
7231
7197
  // src/commands/db/sync/schema-guardrail-graph.ts
@@ -7236,11 +7202,11 @@ function loadSqlSources(targetDir, config) {
7236
7202
  };
7237
7203
  }
7238
7204
  function buildSchemaNodes(params) {
7239
- return stableSorted4(
7205
+ return stableSorted(
7240
7206
  [...params.schemaClaims.entries()].map(([name, files]) => ({
7241
7207
  name,
7242
- claimFiles: normalizeFileList2(files),
7243
- createSchemaFiles: normalizeFileList2(params.createSchemaClaims.get(name) ?? [])
7208
+ claimFiles: normalizeFileList(files),
7209
+ createSchemaFiles: normalizeFileList(params.createSchemaClaims.get(name) ?? [])
7244
7210
  })),
7245
7211
  (value) => value.name
7246
7212
  );
@@ -7253,9 +7219,9 @@ function createSchemaGraphManifest(params) {
7253
7219
  generatorVersion: GENERATOR_VERSION,
7254
7220
  files: params.fileNodes,
7255
7221
  schemas: params.schemaNodes,
7256
- tables: stableSorted4(params.tableNodesByName.values(), (value) => value.qualifiedName),
7222
+ tables: stableSorted(params.tableNodesByName.values(), (value) => value.qualifiedName),
7257
7223
  functionClaims: params.functionClaims,
7258
- policyClaims: stableSorted4(
7224
+ policyClaims: stableSorted(
7259
7225
  params.policyClaims,
7260
7226
  (value) => `${value.targetTable}.${value.name}.${value.sourceFile}`
7261
7227
  ),
@@ -7282,7 +7248,12 @@ async function buildStaticGraph(targetDir, config, sources) {
7282
7248
  const records = await Promise.all(
7283
7249
  declarativeFiles.map((file) => buildDeclarativeFileRecord(file))
7284
7250
  );
7251
+ const functionAclManifest = buildFunctionAclManifestFromSqlFiles(declarativeFiles);
7285
7252
  const idempotentTouchMetadata = buildIdempotentTouchMetadata(idempotentFiles);
7253
+ idempotentTouchMetadata.set(
7254
+ FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
7255
+ buildFunctionAclIdempotentTouchMetadata(functionAclManifest)
7256
+ );
7286
7257
  const { tableOwnerClaims, schemaClaims, createSchemaClaims, tablePolicies, policyClaims } = collectDeclarativeClaims(records);
7287
7258
  const duplicateTableOwners = createDuplicateTableOwners(tableOwnerClaims);
7288
7259
  const { duplicateFunctionOwners, functionClaims } = buildFunctionValidationArtifacts({
@@ -7344,7 +7315,7 @@ async function buildStaticGraph(targetDir, config, sources) {
7344
7315
  policyClaims,
7345
7316
  fileDependencies
7346
7317
  });
7347
- const multiFileSchemas = stableSorted4(
7318
+ const multiFileSchemas = stableSorted(
7348
7319
  graph.schemas.filter((schemaNode) => schemaNode.claimFiles.length > 1).map((schemaNode) => ({
7349
7320
  schema: schemaNode.name,
7350
7321
  files: schemaNode.claimFiles
@@ -7376,6 +7347,7 @@ async function buildStaticGraph(targetDir, config, sources) {
7376
7347
  });
7377
7348
  return {
7378
7349
  graph,
7350
+ functionAclManifest,
7379
7351
  duplicateTableOwners,
7380
7352
  duplicateFunctionOwners,
7381
7353
  policyOwnershipConflicts,
@@ -7392,8 +7364,8 @@ var GUARDRAIL_PHASE_LABELS = {
7392
7364
  load_sources: "Load declarative SQL sources",
7393
7365
  build_static_graph: "Build static SQL graph",
7394
7366
  validate_ownership: "Validate ownership",
7395
- compare_generated_headers: "Compare generated headers",
7396
- refresh_generated_headers: "Refresh generated headers",
7367
+ compare_generated_headers: "Compare generated SQL artifacts",
7368
+ refresh_generated_headers: "Refresh generated SQL artifacts",
7397
7369
  handoff_db_sync: "Hand off to db sync",
7398
7370
  runtime_reconcile: "Runtime reconcile",
7399
7371
  publish_report: "Publish report"
@@ -7482,7 +7454,7 @@ function createCheckModePhases(report) {
7482
7454
  details: {
7483
7455
  file: block.file,
7484
7456
  target: block.target,
7485
- repair: "Run `runa db sync` to auto-regenerate headers"
7457
+ repair: "Run `runa db sync` to auto-regenerate managed SQL artifacts"
7486
7458
  }
7487
7459
  }))
7488
7460
  })
@@ -7984,12 +7956,35 @@ function buildHeaderRewritePlans(params) {
7984
7956
  }
7985
7957
  function loadHeaderRewritePlans(params) {
7986
7958
  try {
7987
- return buildHeaderRewritePlans({
7959
+ const headerPlans = buildHeaderRewritePlans({
7988
7960
  targetDir: params.targetDir,
7989
7961
  graph: params.graph,
7990
7962
  tableHeaderMaxWidth: params.config.tableHeaderMaxWidth,
7991
7963
  generatedHeaderRewriteTargets: params.config.generatedHeaderRewriteTargets
7992
7964
  });
7965
+ const generatedFileResult = buildGeneratedFileRewritePlans({
7966
+ targetDir: params.targetDir,
7967
+ manifest: params.functionAclManifest
7968
+ });
7969
+ if ("failure" in generatedFileResult) {
7970
+ const failureMessage = generatedFileResult.failure ?? "Unknown function ACL migration failure";
7971
+ return {
7972
+ failure: {
7973
+ graph: params.graph,
7974
+ report: setFailure2(
7975
+ params.report,
7976
+ "compare_generated_headers",
7977
+ "function_acl_migration_required",
7978
+ failureMessage
7979
+ )
7980
+ }
7981
+ };
7982
+ }
7983
+ return {
7984
+ staleBlocks: [...headerPlans.staleBlocks, ...generatedFileResult.staleBlocks],
7985
+ rewritePlans: headerPlans.rewritePlans,
7986
+ generatedFileRewritePlans: generatedFileResult.rewritePlans
7987
+ };
7993
7988
  } catch (error) {
7994
7989
  const message = error instanceof Error ? error.message : String(error);
7995
7990
  return {
@@ -8018,7 +8013,7 @@ function finalizeCheckModeReport(params) {
8018
8013
  params.report,
8019
8014
  "compare_generated_headers",
8020
8015
  "stale_generated_header",
8021
- `Generated headers are stale in ${params.report.staleBlocks.map((value) => `${value.file}:${value.kind}`).join(", ")}`
8016
+ `Generated SQL artifacts are stale in ${params.report.staleBlocks.map((value) => `${value.file}:${value.kind}`).join(", ")}`
8022
8017
  )
8023
8018
  };
8024
8019
  }
@@ -8037,6 +8032,15 @@ function rewriteManagedHeaders(params) {
8037
8032
  writeFileSync(path12.join(params.targetDir, plan.filePath), rewrittenSql, "utf-8");
8038
8033
  params.report.headersRewritten.push(plan.filePath);
8039
8034
  }
8035
+ for (const plan of params.generatedFileRewritePlans) {
8036
+ const absolutePath = path12.join(params.targetDir, plan.filePath);
8037
+ const currentSql = existsSync(absolutePath) ? readFileSync(absolutePath, "utf-8") : "";
8038
+ if (normalizeMultilineText(currentSql) === normalizeMultilineText(plan.expectedSql)) {
8039
+ continue;
8040
+ }
8041
+ writeFileSync(absolutePath, plan.expectedSql, "utf-8");
8042
+ params.report.headersRewritten.push(plan.filePath);
8043
+ }
8040
8044
  } catch (error) {
8041
8045
  const message = error instanceof Error ? error.message : String(error);
8042
8046
  return {
@@ -8054,6 +8058,41 @@ function rewriteManagedHeaders(params) {
8054
8058
  params.report.staleBlocks = [];
8055
8059
  return null;
8056
8060
  }
8061
+ function buildGeneratedFileRewritePlans(params) {
8062
+ const absolutePath = path12.join(params.targetDir, FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH);
8063
+ const fileExists = existsSync(absolutePath);
8064
+ const existingSql = fileExists ? readFileSync(absolutePath, "utf-8") : "";
8065
+ if (!fileExists && !functionAclManifestHasEntries(params.manifest)) {
8066
+ return {
8067
+ staleBlocks: [],
8068
+ rewritePlans: []
8069
+ };
8070
+ }
8071
+ if (fileExists) {
8072
+ const migrationGaps = validateFunctionAclMigration(params.manifest, existingSql);
8073
+ if (migrationGaps.length > 0) {
8074
+ return {
8075
+ failure: `Function ACL migration is required before auto-generation can proceed. Add declarative annotations for: ${migrationGaps.join(", ")}`
8076
+ };
8077
+ }
8078
+ }
8079
+ const staleBlocks = !fileExists || isManagedFunctionAclFileContentStale(params.manifest, existingSql) ? [
8080
+ {
8081
+ file: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
8082
+ kind: "generated-file",
8083
+ target: `file:${FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH}`
8084
+ }
8085
+ ] : [];
8086
+ return {
8087
+ staleBlocks,
8088
+ rewritePlans: [
8089
+ {
8090
+ filePath: FUNCTION_ACL_RECONCILIATION_RELATIVE_PATH,
8091
+ expectedSql: renderFunctionAclFile(params.manifest)
8092
+ }
8093
+ ]
8094
+ };
8095
+ }
8057
8096
 
8058
8097
  // src/commands/db/sync/schema-guardrail.ts
8059
8098
  function createEmptyReport(mode) {
@@ -8125,7 +8164,7 @@ function validateLocalBlindSpotBlockers(report, graph) {
8125
8164
  if (!primary) {
8126
8165
  return null;
8127
8166
  }
8128
- const failureCode = primary.kind === "cross-schema-rls" ? "raw_cross_schema_rls_blocked" : primary.kind === "dynamic-sql" ? "dynamic_sql_blocked" : "extension_placement_blocked";
8167
+ const failureCode = primary.kind === "cross-schema-rls" ? "raw_cross_schema_rls_blocked" : primary.kind === "dynamic-sql" || primary.kind === "dynamic-sql-infra" ? "dynamic_sql_blocked" : "extension_placement_blocked";
8129
8168
  return {
8130
8169
  graph,
8131
8170
  report: setFailure3(report, "validate_ownership", failureCode, primary.details)
@@ -8216,6 +8255,7 @@ async function runSchemaGuardrailStatic(input) {
8216
8255
  const headerPlanResult = loadHeaderRewritePlans({
8217
8256
  targetDir: input.targetDir,
8218
8257
  graph: staticGraphResult.graph,
8258
+ functionAclManifest: staticGraphResult.functionAclManifest,
8219
8259
  config,
8220
8260
  report
8221
8261
  });
@@ -8237,6 +8277,7 @@ async function runSchemaGuardrailStatic(input) {
8237
8277
  const rewriteFailure = rewriteManagedHeaders({
8238
8278
  targetDir: input.targetDir,
8239
8279
  rewritePlans: headerPlanResult.rewritePlans,
8280
+ generatedFileRewritePlans: headerPlanResult.generatedFileRewritePlans,
8240
8281
  report
8241
8282
  });
8242
8283
  if (rewriteFailure) {