@cat-factory/app 0.217.2 → 0.218.0

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.
@@ -11,6 +11,12 @@ export type {
11
11
  MergeClassRollup,
12
12
  MergeClassRule,
13
13
  MergeClassRules,
14
+ RuleableChangeClass,
15
+ // The ROLE layer of a preset: per-role narrowing of the rules above, and the roles whose
16
+ // runs are sandboxed (they open a pull request and merge nothing).
17
+ ClassRulesByRole,
18
+ DryRunRoles,
19
+ WorkspaceRole,
14
20
  MergeTrackRecord,
15
21
  ReviewEffort,
16
22
  RequirementConcernLevel,
@@ -1,6 +1,11 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import type { RiskPolicy } from '~/types/merge'
3
- import { RISK_POLICY_AXES, RISK_POLICY_CEILING_FIELD, riskPolicyCeilings } from '~/utils/riskPolicy'
3
+ import {
4
+ RISK_POLICY_AXES,
5
+ RISK_POLICY_CEILING_FIELD,
6
+ riskPolicyCeilings,
7
+ rolePolicySummary,
8
+ } from '~/utils/riskPolicy'
4
9
 
5
10
  const policy = (over: Partial<RiskPolicy> = {}): RiskPolicy =>
6
11
  ({
@@ -20,6 +25,8 @@ const policy = (over: Partial<RiskPolicy> = {}): RiskPolicy =>
20
25
  judgeMaxBounces: 2,
21
26
  autoMergeEnabled: true,
22
27
  classRules: {},
28
+ classRulesByRole: {},
29
+ dryRunRoles: [],
23
30
  isDefault: true,
24
31
  version: 1,
25
32
  createdAt: 0,
@@ -51,3 +58,27 @@ describe('riskPolicyCeilings', () => {
51
58
  expect(Object.keys(RISK_POLICY_CEILING_FIELD).sort()).toEqual([...RISK_POLICY_AXES].sort())
52
59
  })
53
60
  })
61
+
62
+ describe('rolePolicySummary', () => {
63
+ it('is empty on a policy that treats every initiator alike', () => {
64
+ expect(rolePolicySummary(policy())).toEqual({ sandboxed: [], narrowed: [] })
65
+ })
66
+
67
+ it('lists both layers in the shared role order', () => {
68
+ const p = policy({
69
+ dryRunRoles: ['viewer', 'member'],
70
+ classRulesByRole: { admin: { schema: 'never' } },
71
+ })
72
+ expect(rolePolicySummary(p)).toEqual({
73
+ sandboxed: ['member', 'viewer'],
74
+ narrowed: ['admin'],
75
+ })
76
+ })
77
+
78
+ // The sandbox outranks the class rules, so naming both for one role would report a second
79
+ // limit that changes nothing about what that role's runs can do.
80
+ it('does not also report class rules for a role the policy sandboxes', () => {
81
+ const p = policy({ dryRunRoles: ['member'], classRulesByRole: { member: { docs: 'never' } } })
82
+ expect(rolePolicySummary(p)).toEqual({ sandboxed: ['member'], narrowed: [] })
83
+ })
84
+ })
@@ -1,4 +1,5 @@
1
- import type { RiskPolicy } from '~/types/merge'
1
+ import { WORKSPACE_ROLES } from '@cat-factory/contracts'
2
+ import type { RiskPolicy, WorkspaceRole } from '~/types/merge'
2
3
 
3
4
  /**
4
5
  * The three axes a `merger` agent scores a pull request on. Presentation order is
@@ -40,3 +41,30 @@ export interface RiskPolicyCeiling {
40
41
  export function riskPolicyCeilings(p: RiskPolicy): RiskPolicyCeiling[] {
41
42
  return RISK_POLICY_AXES.map((axis) => ({ axis, max: p[RISK_POLICY_CEILING_FIELD[axis]] }))
42
43
  }
44
+
45
+ /** What a policy's ROLE layer does, for the surfaces that explain a policy rather than edit it. */
46
+ export interface RolePolicySummary {
47
+ /** Roles whose runs are sandboxed: they open a pull request and merge nothing. */
48
+ sandboxed: WorkspaceRole[]
49
+ /**
50
+ * Roles held to stricter per-class rules than the base map. A sandboxed role is NOT listed
51
+ * here even when it also carries class rules: the sandbox already outranks them, so naming
52
+ * both would read as two limits where the second changes nothing.
53
+ */
54
+ narrowed: WorkspaceRole[]
55
+ }
56
+
57
+ /**
58
+ * A policy's role layer, in the shared role order so every surface names the tiers the same way.
59
+ * Both lists are empty on a policy that treats every initiator alike, which is every built-in, so
60
+ * a surface can render the whole section conditionally on that.
61
+ */
62
+ export function rolePolicySummary(p: RiskPolicy): RolePolicySummary {
63
+ const sandboxed = WORKSPACE_ROLES.filter((role) => p.dryRunRoles.includes(role))
64
+ return {
65
+ sandboxed: [...sandboxed],
66
+ narrowed: WORKSPACE_ROLES.filter(
67
+ (role) => !sandboxed.includes(role) && Object.keys(p.classRulesByRole[role] ?? {}).length > 0,
68
+ ),
69
+ }
70
+ }
@@ -522,6 +522,19 @@
522
522
  "always": "Immer automatisch zusammenführen",
523
523
  "never": "Immer Review verlangen"
524
524
  }
525
+ },
526
+ "roleRules": {
527
+ "heading": "Grenzen je startender Rolle",
528
+ "help": "Was ein Lauf darf, hängt auch davon ab, wer ihn gestartet hat. Eine Rolle kann strengeren Regeln als den obigen unterliegen oder nur Probeläufe machen: Die Pipeline arbeitet und öffnet einen Pull Request, zusammengeführt wird nichts. Eine Rolle kann diese Richtlinie nur verschärfen, nie lockern.",
529
+ "autoMergeOffWarning": "Für diese Vorlage ist das automatische Zusammenführen aus, jeder Pull Request geht also ohnehin an einen Menschen und die Kategoriegrenzen unten ändern nichts mehr. Probeläufe gelten weiterhin: Sie verweigern auch das manuelle Zusammenführen.",
530
+ "sandboxLabel": "Nur Probeläufe",
531
+ "sandboxNote": "Läufe dieser Rolle öffnen einen Pull Request und führen nichts zusammen, die Kategorieregeln unten können sie also nicht weiter einschränken.",
532
+ "noRules": "Keine Kategoriegrenzen",
533
+ "ruleCount": "{count} Kategorie eingeschränkt | {count} Kategorien eingeschränkt",
534
+ "inherit": "Wie in dieser Richtlinie",
535
+ "redundant": "Ohne Wirkung: Diese Richtlinie ist bereits mindestens so streng.",
536
+ "alreadyStrictest": "Wird ohnehin immer geprüft",
537
+ "baseHint": "Diese Richtlinie vergleicht in jeder Kategorie die Bewertungen, eine Rolle kann eine Kategorie daher nur auf \"immer Review\" verschärfen."
525
538
  }
526
539
  },
527
540
  "observabilityConnection": {
@@ -1539,7 +1552,9 @@
1539
1552
  "chooseApproach": "Ansatz wählen",
1540
1553
  "triageFollowUps": "Folgeaufgaben entscheiden",
1541
1554
  "elapsedTooltip": "Verstrichene Zeit für diesen Schritt",
1542
- "reviewFindings": "Befunde prüfen"
1555
+ "reviewFindings": "Befunde prüfen",
1556
+ "dryRun": "Probelauf",
1557
+ "dryRunHint": "Dieser Lauf öffnet einen Pull Request und führt nichts zusammen."
1543
1558
  },
1544
1559
  "structure": {
1545
1560
  "title": "Struktur",
@@ -1960,7 +1975,10 @@
1960
1975
  "title": "Diesen Dienst archivieren?",
1961
1976
  "body": "„{name}“ und seine Aufgaben werden vom Board ausgeblendet. Du kannst den Dienst jederzeit wiederherstellen."
1962
1977
  },
1963
- "runBlocked": "Blockiert durch eine unerledigte Abhängigkeit: {names} | Blockiert durch {count} unerledigte Abhängigkeiten: {names}"
1978
+ "runBlocked": "Blockiert durch eine unerledigte Abhängigkeit: {names} | Blockiert durch {count} unerledigte Abhängigkeiten: {names}",
1979
+ "dryRun": "Probelauf: nichts zusammenführen",
1980
+ "dryRunForced": "Probelauf: Läufe deiner Rolle werden hier nie zusammengeführt",
1981
+ "dryRunHint": "Dieser Lauf öffnet einen Pull Request und führt nichts zusammen."
1964
1982
  }
1965
1983
  },
1966
1984
  "layout": {
@@ -2819,6 +2837,7 @@
2819
2837
  "start": "Starten",
2820
2838
  "blocked": "Blockiert",
2821
2839
  "startPipeline": "{name} starten",
2840
+ "startPipelineDryRun": "{name} als Probelauf starten: öffnet einen Pull Request, führt nichts zusammen",
2822
2841
  "pipelineFallback": "Pipeline",
2823
2842
  "waitingOn": "Wartet auf: {deps}",
2824
2843
  "blockedByDependenciesTitle": "Durch Abhängigkeiten blockiert",
@@ -2844,6 +2863,10 @@
2844
2863
  "reviewAndApprove": "Überprüfen & freigeben",
2845
2864
  "clickToViewStep": "Klicken, um Schrittdetails & Ausgabe anzuzeigen"
2846
2865
  },
2866
+ "dryRunToast": {
2867
+ "title": "Probelauf gestartet",
2868
+ "body": "\"{name}\" läuft. Läufe deiner Rolle führen bei dieser Aufgabe nichts zusammen."
2869
+ },
2847
2870
  "epic": {
2848
2871
  "label": "Epic",
2849
2872
  "activeCount": "{count} aktiv",
@@ -5779,7 +5802,10 @@
5779
5802
  "description": "Beschreibung",
5780
5803
  "overallProgress": "Gesamtfortschritt",
5781
5804
  "dependencies": "Abhängigkeiten",
5782
- "noDependencies": "Keine"
5805
+ "noDependencies": "Keine",
5806
+ "dryRun": "Probelauf",
5807
+ "dryRunHint": "Die Pipeline ausführen und einen Pull Request öffnen, aber nichts zusammenführen.",
5808
+ "dryRunForcedHint": "Die Risikorichtlinie dieser Aufgabe lässt deine Rolle nur Probeläufe machen."
5783
5809
  },
5784
5810
  "environments": {
5785
5811
  "title": "Ephemere Umgebung",
@@ -6046,7 +6072,10 @@
6046
6072
  "manualHeading": "Nur manuelle Prüfung",
6047
6073
  "manualExplainer": "Diese Richtlinie mergt nie von selbst, jeder Pull Request wartet also unabhängig von den Bewertungen auf eine menschliche Prüfung.",
6048
6074
  "ciHeading": "CI-Fixes",
6049
- "ciAttempts": "Der Lauf darf {count} Mal versuchen, eine rote CI grün zu bekommen, bevor er aufgibt. | Der Lauf darf {count} Mal versuchen, eine rote CI grün zu bekommen, bevor er aufgibt."
6075
+ "ciAttempts": "Der Lauf darf {count} Mal versuchen, eine rote CI grün zu bekommen, bevor er aufgibt. | Der Lauf darf {count} Mal versuchen, eine rote CI grün zu bekommen, bevor er aufgibt.",
6076
+ "roleHeading": "Wer den Lauf gestartet hat",
6077
+ "roleSandboxed": "Läufe von {roles} öffnen einen Pull Request und werden nie zusammengeführt.",
6078
+ "roleNarrowed": "Für Läufe von {roles} gelten in einigen Änderungskategorien strengere Regeln."
6050
6079
  }
6051
6080
  },
6052
6081
  "modelPreset": {
@@ -492,6 +492,7 @@
492
492
  "start": "Start",
493
493
  "blocked": "Blocked",
494
494
  "startPipeline": "Start {name}",
495
+ "startPipelineDryRun": "Start {name} as a dry run: opens a pull request, merges nothing",
495
496
  "pipelineFallback": "pipeline",
496
497
  "waitingOn": "Waiting on: {deps}",
497
498
  "blockedByDependenciesTitle": "Blocked by dependencies",
@@ -517,6 +518,13 @@
517
518
  "reviewAndApprove": "Review & approve",
518
519
  "clickToViewStep": "Click to view step details & output"
519
520
  },
521
+ "dryRunToast": {
522
+ "title": "Dry run started",
523
+ "body": "Running \"{name}\". Your role's runs merge nothing on this task."
524
+ },
525
+ "@dryRunToast": {
526
+ "description": "Toast shown when a run starts that the task's merge policy has sandboxed because of the initiator's workspace role: the pipeline runs and opens a pull request, and nothing merges. {name} is the pipeline name, kept verbatim. Not a choice the reader made, so word it as a statement of what the run will do rather than as a confirmation of a setting."
527
+ },
520
528
  "epic": {
521
529
  "label": "Epic",
522
530
  "activeCount": "{count} active",
@@ -1155,7 +1163,9 @@
1155
1163
  "chooseApproach": "Choose approach",
1156
1164
  "triageFollowUps": "Decide follow-ups",
1157
1165
  "elapsedTooltip": "Elapsed time on this step",
1158
- "reviewFindings": "Review findings"
1166
+ "reviewFindings": "Review findings",
1167
+ "dryRun": "Dry run",
1168
+ "dryRunHint": "This run opens a pull request and merges nothing."
1159
1169
  },
1160
1170
  "structure": {
1161
1171
  "title": "Structure",
@@ -1584,7 +1594,10 @@
1584
1594
  "runBlocked": "Blocked by an unfinished dependency: {names} | Blocked by {count} unfinished dependencies: {names}",
1585
1595
  "@runBlocked": {
1586
1596
  "description": "Count-driven plural: {count} unfinished dependencies, {names} their comma-joined titles. Languages with more than two plural forms (e.g. Polish, Ukrainian: one/few/many) need the extra pipe-separated forms."
1587
- }
1597
+ },
1598
+ "dryRun": "Dry run: merge nothing",
1599
+ "dryRunForced": "Dry run: your role's runs never merge here",
1600
+ "dryRunHint": "This run opens a pull request and merges nothing."
1588
1601
  }
1589
1602
  },
1590
1603
  "observability": {
@@ -2977,6 +2990,22 @@
2977
2990
  "always": "Always auto-merge",
2978
2991
  "never": "Always require review"
2979
2992
  }
2993
+ },
2994
+ "roleRules": {
2995
+ "heading": "Limits per initiator role",
2996
+ "help": "What a run may do also depends on who started it. A role can be held to stricter rules than the ones above, or to dry runs only: the pipeline works and opens a pull request, and nothing merges. A role can only narrow this policy, never widen it.",
2997
+ "autoMergeOffWarning": "Auto-merge is off for this preset, so every pull request already goes to a human and the class limits below add nothing. Dry runs still apply: they refuse a manual merge too.",
2998
+ "sandboxLabel": "Dry runs only",
2999
+ "sandboxNote": "Runs started by this role open a pull request and merge nothing, so the class rules below cannot hold them to anything stricter.",
3000
+ "noRules": "No class limits",
3001
+ "ruleCount": "{count} class limited | {count} classes limited",
3002
+ "@ruleCount": {
3003
+ "description": "Count-based tally of how many change classes this role narrows (count is always >= 1). Provide ALL plural forms your language needs (English has 2; Polish/Ukrainian need 3 - one/few/many - via the custom pluralRules in i18n.config.ts)."
3004
+ },
3005
+ "inherit": "Same as this policy",
3006
+ "redundant": "No effect: this policy is already at least as strict.",
3007
+ "alreadyStrictest": "Already always reviewed",
3008
+ "baseHint": "This policy compares the scores for every class, so a role can only narrow a class to review-only."
2980
3009
  }
2981
3010
  },
2982
3011
  "observabilityConnection": {
@@ -4634,7 +4663,10 @@
4634
4663
  "manualHeading": "Manual review only",
4635
4664
  "manualExplainer": "This policy never merges on its own, so every pull request waits for a human review whatever it scores.",
4636
4665
  "ciHeading": "CI fixes",
4637
- "ciAttempts": "The run may try {count} time to turn a red CI green before it gives up. | The run may try {count} times to turn a red CI green before it gives up."
4666
+ "ciAttempts": "The run may try {count} time to turn a red CI green before it gives up. | The run may try {count} times to turn a red CI green before it gives up.",
4667
+ "roleHeading": "Who started the run",
4668
+ "roleSandboxed": "Runs started by {roles} open a pull request and never merge.",
4669
+ "roleNarrowed": "Runs started by {roles} follow stricter rules for some change classes."
4638
4670
  }
4639
4671
  },
4640
4672
  "modelPreset": {
@@ -5463,7 +5495,10 @@
5463
5495
  "description": "Description",
5464
5496
  "overallProgress": "Overall progress",
5465
5497
  "dependencies": "Dependencies",
5466
- "noDependencies": "None"
5498
+ "noDependencies": "None",
5499
+ "dryRun": "Dry run",
5500
+ "dryRunHint": "Run the pipeline and open a pull request, but merge nothing.",
5501
+ "dryRunForcedHint": "This task's risk policy holds your role to dry runs."
5467
5502
  },
5468
5503
  "environments": {
5469
5504
  "title": "Ephemeral environment",
@@ -447,6 +447,7 @@
447
447
  "start": "Iniciar",
448
448
  "blocked": "Bloqueada",
449
449
  "startPipeline": "Iniciar {name}",
450
+ "startPipelineDryRun": "Iniciar {name} como ejecución de prueba: abre una pull request y no fusiona nada",
450
451
  "pipelineFallback": "pipeline",
451
452
  "waitingOn": "Esperando a: {deps}",
452
453
  "blockedByDependenciesTitle": "Bloqueada por dependencias",
@@ -472,6 +473,10 @@
472
473
  "body": "Ejecutando \"{name}\"."
473
474
  }
474
475
  },
476
+ "dryRunToast": {
477
+ "title": "Ejecución de prueba iniciada",
478
+ "body": "Ejecutando \"{name}\". Las ejecuciones de tu rol no fusionan nada en esta tarea."
479
+ },
475
480
  "epic": {
476
481
  "label": "Épica",
477
482
  "activeCount": "{count} activas",
@@ -1077,7 +1082,9 @@
1077
1082
  "chooseApproach": "Elegir enfoque",
1078
1083
  "triageFollowUps": "Decidir seguimientos",
1079
1084
  "elapsedTooltip": "Tiempo transcurrido en este paso",
1080
- "reviewFindings": "Revisar hallazgos"
1085
+ "reviewFindings": "Revisar hallazgos",
1086
+ "dryRun": "Ejecución de prueba",
1087
+ "dryRunHint": "Esta ejecución abre una pull request y no fusiona nada."
1081
1088
  },
1082
1089
  "structure": {
1083
1090
  "title": "Estructura",
@@ -1498,7 +1505,10 @@
1498
1505
  "title": "¿Archivar este servicio?",
1499
1506
  "body": "«{name}» y sus tareas se ocultarán del tablero. Puedes restaurarlo en cualquier momento."
1500
1507
  },
1501
- "runBlocked": "Bloqueado por una dependencia sin terminar: {names} | Bloqueado por {count} dependencias sin terminar: {names}"
1508
+ "runBlocked": "Bloqueado por una dependencia sin terminar: {names} | Bloqueado por {count} dependencias sin terminar: {names}",
1509
+ "dryRun": "Ejecución de prueba: no fusionar nada",
1510
+ "dryRunForced": "Ejecución de prueba: las ejecuciones de tu rol nunca se fusionan aquí",
1511
+ "dryRunHint": "Esta ejecución abre una pull request y no fusiona nada."
1502
1512
  }
1503
1513
  },
1504
1514
  "observability": {
@@ -2738,6 +2748,19 @@
2738
2748
  "always": "Fusionar siempre automáticamente",
2739
2749
  "never": "Exigir siempre revisión"
2740
2750
  }
2751
+ },
2752
+ "roleRules": {
2753
+ "heading": "Límites según el rol que inicia",
2754
+ "help": "Lo que puede hacer una ejecución también depende de quién la inició. Un rol puede quedar sujeto a reglas más estrictas que las de arriba, o solo a ejecuciones de prueba: la canalización trabaja y abre una pull request, pero no se fusiona nada. Un rol solo puede endurecer esta política, nunca relajarla.",
2755
+ "autoMergeOffWarning": "El auto-merge está desactivado en este preajuste, así que cada pull request ya pasa por una persona y los límites de categoría de abajo no añaden nada. Las ejecuciones de prueba siguen aplicándose: también rechazan una fusión manual.",
2756
+ "sandboxLabel": "Solo ejecuciones de prueba",
2757
+ "sandboxNote": "Las ejecuciones iniciadas por este rol abren una pull request y no fusionan nada, así que las reglas por categoría de abajo no pueden restringirlas más.",
2758
+ "noRules": "Sin límites por categoría",
2759
+ "ruleCount": "{count} categoría limitada | {count} categorías limitadas",
2760
+ "inherit": "Igual que esta política",
2761
+ "redundant": "Sin efecto: esta política ya es igual de estricta o más.",
2762
+ "alreadyStrictest": "Ya se revisa siempre",
2763
+ "baseHint": "Esta política compara las puntuaciones en todas las categorías, así que un rol solo puede endurecer una categoría hasta exigir revisión."
2741
2764
  }
2742
2765
  },
2743
2766
  "observabilityConnection": {
@@ -5224,7 +5247,10 @@
5224
5247
  "description": "Descripción",
5225
5248
  "overallProgress": "Progreso general",
5226
5249
  "dependencies": "Dependencias",
5227
- "noDependencies": "Ninguna"
5250
+ "noDependencies": "Ninguna",
5251
+ "dryRun": "Ejecución de prueba",
5252
+ "dryRunHint": "Ejecutar la canalización y abrir una pull request, pero no fusionar nada.",
5253
+ "dryRunForcedHint": "La política de riesgo de esta tarea limita tu rol a ejecuciones de prueba."
5228
5254
  },
5229
5255
  "environments": {
5230
5256
  "title": "Entorno efímero",
@@ -5913,7 +5939,10 @@
5913
5939
  "manualHeading": "Solo revisión manual",
5914
5940
  "manualExplainer": "Esta política nunca fusiona por su cuenta, así que cada pull request espera una revisión humana sea cual sea su puntuación.",
5915
5941
  "ciHeading": "Correcciones de CI",
5916
- "ciAttempts": "La ejecución puede intentar {count} vez poner CI en verde antes de rendirse. | La ejecución puede intentar {count} veces poner CI en verde antes de rendirse."
5942
+ "ciAttempts": "La ejecución puede intentar {count} vez poner CI en verde antes de rendirse. | La ejecución puede intentar {count} veces poner CI en verde antes de rendirse.",
5943
+ "roleHeading": "Quién inició la ejecución",
5944
+ "roleSandboxed": "Las ejecuciones iniciadas por {roles} abren una pull request y nunca se fusionan.",
5945
+ "roleNarrowed": "Las ejecuciones iniciadas por {roles} siguen reglas más estrictas en algunas categorías de cambio."
5917
5946
  }
5918
5947
  },
5919
5948
  "modelPreset": {
@@ -447,6 +447,7 @@
447
447
  "start": "Démarrer",
448
448
  "blocked": "Bloquée",
449
449
  "startPipeline": "Démarrer {name}",
450
+ "startPipelineDryRun": "Démarrer {name} en exécution à blanc : ouvre une pull request, ne fusionne rien",
450
451
  "pipelineFallback": "pipeline",
451
452
  "waitingOn": "En attente de : {deps}",
452
453
  "blockedByDependenciesTitle": "Bloquée par des dépendances",
@@ -472,6 +473,10 @@
472
473
  "body": "Exécution de \"{name}\"."
473
474
  }
474
475
  },
476
+ "dryRunToast": {
477
+ "title": "Exécution à blanc démarrée",
478
+ "body": "Exécution de \"{name}\". Les exécutions de ton rôle ne fusionnent rien sur cette tâche."
479
+ },
475
480
  "epic": {
476
481
  "label": "Épopée",
477
482
  "activeCount": "{count} actives",
@@ -1077,7 +1082,9 @@
1077
1082
  "chooseApproach": "Choisir l'approche",
1078
1083
  "triageFollowUps": "Trancher les suivis",
1079
1084
  "elapsedTooltip": "Temps écoulé sur cette étape",
1080
- "reviewFindings": "Examiner les remarques"
1085
+ "reviewFindings": "Examiner les remarques",
1086
+ "dryRun": "Exécution à blanc",
1087
+ "dryRunHint": "Cette exécution ouvre une pull request et ne fusionne rien."
1081
1088
  },
1082
1089
  "structure": {
1083
1090
  "title": "Structure",
@@ -1498,7 +1505,10 @@
1498
1505
  "title": "Archiver ce service ?",
1499
1506
  "body": "« {name} » et ses tâches seront masqués du tableau. Vous pouvez le restaurer à tout moment."
1500
1507
  },
1501
- "runBlocked": "Bloqué par une dépendance non terminée : {names} | Bloqué par {count} dépendances non terminées : {names}"
1508
+ "runBlocked": "Bloqué par une dépendance non terminée : {names} | Bloqué par {count} dépendances non terminées : {names}",
1509
+ "dryRun": "Exécution à blanc : ne rien fusionner",
1510
+ "dryRunForced": "Exécution à blanc : les exécutions de votre rôle ne sont jamais fusionnées ici",
1511
+ "dryRunHint": "Cette exécution ouvre une pull request et ne fusionne rien."
1502
1512
  }
1503
1513
  },
1504
1514
  "observability": {
@@ -2738,6 +2748,19 @@
2738
2748
  "always": "Toujours fusionner automatiquement",
2739
2749
  "never": "Toujours exiger une revue"
2740
2750
  }
2751
+ },
2752
+ "roleRules": {
2753
+ "heading": "Limites selon le rôle qui lance l'exécution",
2754
+ "help": "Ce qu'une exécution peut faire dépend aussi de qui l'a lancée. Un rôle peut être soumis à des règles plus strictes que celles ci-dessus, ou aux seules exécutions à blanc : le pipeline travaille et ouvre une pull request, mais rien n'est fusionné. Un rôle peut seulement durcir cette politique, jamais l'assouplir.",
2755
+ "autoMergeOffWarning": "La fusion automatique est désactivée pour ce préréglage : chaque pull request passe déjà par un humain et les limites de catégorie ci-dessous n'ajoutent rien. Les exécutions à blanc restent en vigueur : elles refusent aussi une fusion manuelle.",
2756
+ "sandboxLabel": "Exécutions à blanc uniquement",
2757
+ "sandboxNote": "Les exécutions lancées par ce rôle ouvrent une pull request et ne fusionnent rien : les règles par catégorie ci-dessous ne peuvent donc rien durcir de plus.",
2758
+ "noRules": "Aucune limite par catégorie",
2759
+ "ruleCount": "{count} catégorie limitée | {count} catégories limitées",
2760
+ "inherit": "Comme cette politique",
2761
+ "redundant": "Sans effet : cette politique est déjà au moins aussi stricte.",
2762
+ "alreadyStrictest": "Déjà toujours relu",
2763
+ "baseHint": "Cette politique compare les scores pour chaque catégorie : un rôle ne peut donc durcir une catégorie que jusqu'à la revue obligatoire."
2741
2764
  }
2742
2765
  },
2743
2766
  "observabilityConnection": {
@@ -5224,7 +5247,10 @@
5224
5247
  "description": "Description",
5225
5248
  "overallProgress": "Progression globale",
5226
5249
  "dependencies": "Dépendances",
5227
- "noDependencies": "Aucune"
5250
+ "noDependencies": "Aucune",
5251
+ "dryRun": "Exécution à blanc",
5252
+ "dryRunHint": "Lancer le pipeline et ouvrir une pull request, sans rien fusionner.",
5253
+ "dryRunForcedHint": "La politique de risque de cette tâche limite votre rôle aux exécutions à blanc."
5228
5254
  },
5229
5255
  "environments": {
5230
5256
  "title": "Environnement éphémère",
@@ -5913,7 +5939,10 @@
5913
5939
  "manualHeading": "Revue manuelle uniquement",
5914
5940
  "manualExplainer": "Cette politique ne fusionne jamais d'elle-même : chaque pull request attend une revue humaine, quelles que soient les notes.",
5915
5941
  "ciHeading": "Corrections CI",
5916
- "ciAttempts": "L'exécution peut tenter {count} fois de remettre la CI au vert avant d'abandonner. | L'exécution peut tenter {count} fois de remettre la CI au vert avant d'abandonner."
5942
+ "ciAttempts": "L'exécution peut tenter {count} fois de remettre la CI au vert avant d'abandonner. | L'exécution peut tenter {count} fois de remettre la CI au vert avant d'abandonner.",
5943
+ "roleHeading": "Qui a lancé l'exécution",
5944
+ "roleSandboxed": "Les exécutions lancées par {roles} ouvrent une pull request et ne sont jamais fusionnées.",
5945
+ "roleNarrowed": "Les exécutions lancées par {roles} suivent des règles plus strictes pour certaines catégories de changement."
5917
5946
  }
5918
5947
  },
5919
5948
  "modelPreset": {
@@ -447,6 +447,7 @@
447
447
  "start": "התחל",
448
448
  "blocked": "חסום",
449
449
  "startPipeline": "התחל {name}",
450
+ "startPipelineDryRun": "להתחיל את {name} כהרצת יבש: נפתחת בקשת משיכה ולא ממוזג דבר",
450
451
  "pipelineFallback": "צינור",
451
452
  "waitingOn": "ממתין ל: {deps}",
452
453
  "blockedByDependenciesTitle": "חסום על ידי תלויות",
@@ -472,6 +473,10 @@
472
473
  "body": "מריץ את \"{name}\"."
473
474
  }
474
475
  },
476
+ "dryRunToast": {
477
+ "title": "הרצת יבש החלה",
478
+ "body": "מריץ את \"{name}\". הרצות של התפקיד שלך לא ממזגות דבר במשימה הזו."
479
+ },
475
480
  "epic": {
476
481
  "label": "אפיק",
477
482
  "activeCount": "{count} פעילים",
@@ -1077,7 +1082,9 @@
1077
1082
  "chooseApproach": "בחר גישה",
1078
1083
  "triageFollowUps": "הכרע בהמשכים",
1079
1084
  "elapsedTooltip": "הזמן שחלף בשלב זה",
1080
- "reviewFindings": "עיין בממצאים"
1085
+ "reviewFindings": "עיין בממצאים",
1086
+ "dryRun": "הרצת יבש",
1087
+ "dryRunHint": "ההרצה הזו פותחת בקשת משיכה ואינה ממזגת דבר."
1081
1088
  },
1082
1089
  "structure": {
1083
1090
  "title": "מבנה",
@@ -1498,7 +1505,10 @@
1498
1505
  "title": "להעביר שירות זה לארכיון?",
1499
1506
  "body": "\"{name}\" והמשימות שלו יוסתרו מהלוח. אפשר לשחזר אותו בכל עת."
1500
1507
  },
1501
- "runBlocked": "חסום על ידי תלות אחת שלא הושלמה: {names} | חסום על ידי שתי תלויות שלא הושלמו: {names} | חסום על ידי {count} תלויות שלא הושלמו: {names}"
1508
+ "runBlocked": "חסום על ידי תלות אחת שלא הושלמה: {names} | חסום על ידי שתי תלויות שלא הושלמו: {names} | חסום על ידי {count} תלויות שלא הושלמו: {names}",
1509
+ "dryRun": "הרצת יבש: לא למזג דבר",
1510
+ "dryRunForced": "הרצת יבש: הרצות של התפקיד שלך לעולם אינן ממוזגות כאן",
1511
+ "dryRunHint": "ההרצה הזו פותחת בקשת משיכה ואינה ממזגת דבר."
1502
1512
  }
1503
1513
  },
1504
1514
  "observability": {
@@ -2879,6 +2889,19 @@
2879
2889
  "always": "למזג תמיד אוטומטית",
2880
2890
  "never": "לדרוש תמיד סקירה"
2881
2891
  }
2892
+ },
2893
+ "roleRules": {
2894
+ "heading": "מגבלות לפי תפקיד המפעיל",
2895
+ "help": "מה שהרצה רשאית לעשות תלוי גם במי שהפעיל אותה. אפשר להחיל על תפקיד כללים מחמירים יותר מאלה שלמעלה, או להגביל אותו להרצות יבשות בלבד: הפייפליין עובד ופותח בקשת משיכה, ושום דבר לא ממוזג. תפקיד יכול רק להחמיר את המדיניות הזו, לעולם לא להקל אותה.",
2896
+ "autoMergeOffWarning": "המיזוג האוטומטי כבוי בהגדרה הזאת, ולכן כל בקשת מיזוג ממילא עוברת לאדם והמגבלות לפי סוג שלמטה כבר לא מוסיפות דבר. הרצות יבשות עדיין חלות: הן מסרבות גם למיזוג ידני.",
2897
+ "sandboxLabel": "הרצות יבשות בלבד",
2898
+ "sandboxNote": "הרצות שמפעיל התפקיד הזה פותחות בקשת משיכה ואינן ממזגות דבר, ולכן הכללים לפי סוג השינוי שלמטה אינם יכולים להחמיר אותן עוד.",
2899
+ "noRules": "אין מגבלות לפי סוג",
2900
+ "ruleCount": "סוג אחד מוגבל | שני סוגים מוגבלים | {count} סוגים מוגבלים",
2901
+ "inherit": "כמו במדיניות הזו",
2902
+ "redundant": "ללא השפעה: המדיניות הזו כבר מחמירה לפחות באותה מידה.",
2903
+ "alreadyStrictest": "כבר תמיד נדרשת סקירה",
2904
+ "baseHint": "המדיניות הזו משווה את הציונים בכל סוג שינוי, ולכן תפקיד יכול להחמיר סוג רק עד דרישת סקירה."
2882
2905
  }
2883
2906
  },
2884
2907
  "observabilityConnection": {
@@ -5224,7 +5247,10 @@
5224
5247
  "description": "תיאור",
5225
5248
  "overallProgress": "התקדמות כוללת",
5226
5249
  "dependencies": "תלויות",
5227
- "noDependencies": "אין"
5250
+ "noDependencies": "אין",
5251
+ "dryRun": "הרצת יבש",
5252
+ "dryRunHint": "להריץ את הפייפליין ולפתוח בקשת משיכה, בלי למזג דבר.",
5253
+ "dryRunForcedHint": "מדיניות הסיכון של המשימה הזו מגבילה את התפקיד שלך להרצות יבשות."
5228
5254
  },
5229
5255
  "environments": {
5230
5256
  "title": "סביבה זמנית",
@@ -5913,7 +5939,10 @@
5913
5939
  "manualHeading": "סקירה ידנית בלבד",
5914
5940
  "manualExplainer": "מדיניות זו לעולם אינה ממזגת מעצמה, ולכן כל בקשת משיכה ממתינה לסקירה אנושית ללא קשר לניקוד.",
5915
5941
  "ciHeading": "תיקוני CI",
5916
- "ciAttempts": "ההרצה רשאית לנסות פעם אחת להחזיר CI אדום למצב ירוק לפני שהיא מוותרת. | ההרצה רשאית לנסות פעמיים להחזיר CI אדום למצב ירוק לפני שהיא מוותרת. | ההרצה רשאית לנסות {count} פעמים להחזיר CI אדום למצב ירוק לפני שהיא מוותרת."
5942
+ "ciAttempts": "ההרצה רשאית לנסות פעם אחת להחזיר CI אדום למצב ירוק לפני שהיא מוותרת. | ההרצה רשאית לנסות פעמיים להחזיר CI אדום למצב ירוק לפני שהיא מוותרת. | ההרצה רשאית לנסות {count} פעמים להחזיר CI אדום למצב ירוק לפני שהיא מוותרת.",
5943
+ "roleHeading": "מי הפעיל את ההרצה",
5944
+ "roleSandboxed": "הרצות שמפעילים {roles} פותחות בקשת משיכה ולעולם אינן ממוזגות.",
5945
+ "roleNarrowed": "על הרצות שמפעילים {roles} חלים כללים מחמירים יותר בחלק מסוגי השינוי."
5917
5946
  }
5918
5947
  },
5919
5948
  "modelPreset": {
@@ -522,6 +522,19 @@
522
522
  "always": "Unisci sempre automaticamente",
523
523
  "never": "Richiedi sempre una revisione"
524
524
  }
525
+ },
526
+ "roleRules": {
527
+ "heading": "Limiti per ruolo di chi avvia",
528
+ "help": "Ciò che un'esecuzione può fare dipende anche da chi l'ha avviata. Un ruolo può essere soggetto a regole più severe di quelle sopra, oppure alle sole prove: la pipeline lavora e apre una pull request, ma non viene unito nulla. Un ruolo può solo restringere questo criterio, mai allargarlo.",
529
+ "autoMergeOffWarning": "L'unione automatica è disattivata per questo preset, quindi ogni pull request passa già da una persona e i limiti per categoria qui sotto non aggiungono nulla. Le prove restano valide: rifiutano anche un'unione manuale.",
530
+ "sandboxLabel": "Solo prove",
531
+ "sandboxNote": "Le esecuzioni avviate da questo ruolo aprono una pull request e non uniscono nulla, quindi le regole per categoria qui sotto non possono restringerle ulteriormente.",
532
+ "noRules": "Nessun limite per categoria",
533
+ "ruleCount": "{count} categoria limitata | {count} categorie limitate",
534
+ "inherit": "Come questo criterio",
535
+ "redundant": "Nessun effetto: questo criterio è già almeno altrettanto severo.",
536
+ "alreadyStrictest": "Già sempre in revisione",
537
+ "baseHint": "Questo criterio confronta i punteggi per ogni categoria, quindi un ruolo può restringere una categoria solo fino alla revisione obbligatoria."
525
538
  }
526
539
  },
527
540
  "observabilityConnection": {
@@ -1539,7 +1552,9 @@
1539
1552
  "chooseApproach": "Scegli approccio",
1540
1553
  "triageFollowUps": "Decidi i follow-up",
1541
1554
  "elapsedTooltip": "Tempo trascorso su questo passaggio",
1542
- "reviewFindings": "Esamina i rilievi"
1555
+ "reviewFindings": "Esamina i rilievi",
1556
+ "dryRun": "Prova",
1557
+ "dryRunHint": "Questa esecuzione apre una pull request e non unisce nulla."
1543
1558
  },
1544
1559
  "structure": {
1545
1560
  "title": "Struttura",
@@ -1960,7 +1975,10 @@
1960
1975
  "title": "Archiviare questo servizio?",
1961
1976
  "body": "\"{name}\" e le sue attività verranno nascosti dalla board. Puoi ripristinarlo in qualsiasi momento."
1962
1977
  },
1963
- "runBlocked": "Bloccato da una dipendenza non completata: {names} | Bloccato da {count} dipendenze non completate: {names}"
1978
+ "runBlocked": "Bloccato da una dipendenza non completata: {names} | Bloccato da {count} dipendenze non completate: {names}",
1979
+ "dryRun": "Prova: non unire nulla",
1980
+ "dryRunForced": "Prova: le esecuzioni del tuo ruolo qui non vengono mai unite",
1981
+ "dryRunHint": "Questa esecuzione apre una pull request e non unisce nulla."
1964
1982
  }
1965
1983
  },
1966
1984
  "layout": {
@@ -2819,6 +2837,7 @@
2819
2837
  "start": "Avvia",
2820
2838
  "blocked": "Bloccato",
2821
2839
  "startPipeline": "Avvia {name}",
2840
+ "startPipelineDryRun": "Avvia {name} come prova: apre una pull request e non unisce nulla",
2822
2841
  "pipelineFallback": "pipeline",
2823
2842
  "waitingOn": "In attesa di: {deps}",
2824
2843
  "blockedByDependenciesTitle": "Bloccato dalle dipendenze",
@@ -2844,6 +2863,10 @@
2844
2863
  "reviewAndApprove": "Rivedi e approva",
2845
2864
  "clickToViewStep": "Clicca per vedere i dettagli e l'output della fase"
2846
2865
  },
2866
+ "dryRunToast": {
2867
+ "title": "Prova avviata",
2868
+ "body": "Esecuzione di \"{name}\". Le esecuzioni del tuo ruolo non uniscono nulla su questa attività."
2869
+ },
2847
2870
  "epic": {
2848
2871
  "label": "Epic",
2849
2872
  "activeCount": "{count} attive",
@@ -5779,7 +5802,10 @@
5779
5802
  "description": "Descrizione",
5780
5803
  "overallProgress": "Avanzamento complessivo",
5781
5804
  "dependencies": "Dipendenze",
5782
- "noDependencies": "Nessuna"
5805
+ "noDependencies": "Nessuna",
5806
+ "dryRun": "Prova",
5807
+ "dryRunHint": "Esegui la pipeline e apri una pull request, senza unire nulla.",
5808
+ "dryRunForcedHint": "Il criterio di rischio di questa attività limita il tuo ruolo alle sole prove."
5783
5809
  },
5784
5810
  "environments": {
5785
5811
  "title": "Ambiente effimero",
@@ -6046,7 +6072,10 @@
6046
6072
  "manualHeading": "Solo revisione manuale",
6047
6073
  "manualExplainer": "Questo criterio non unisce mai da solo, quindi ogni pull request attende una revisione umana qualunque sia il punteggio.",
6048
6074
  "ciHeading": "Correzioni CI",
6049
- "ciAttempts": "L'esecuzione può fare {count} tentativo per rimettere in verde la CI prima di arrendersi. | L'esecuzione può fare {count} tentativi per rimettere in verde la CI prima di arrendersi."
6075
+ "ciAttempts": "L'esecuzione può fare {count} tentativo per rimettere in verde la CI prima di arrendersi. | L'esecuzione può fare {count} tentativi per rimettere in verde la CI prima di arrendersi.",
6076
+ "roleHeading": "Chi ha avviato l'esecuzione",
6077
+ "roleSandboxed": "Le esecuzioni avviate da {roles} aprono una pull request e non vengono mai unite.",
6078
+ "roleNarrowed": "Le esecuzioni avviate da {roles} seguono regole più severe per alcune categorie di modifica."
6050
6079
  }
6051
6080
  },
6052
6081
  "modelPreset": {