@cat-factory/app 0.157.0 → 0.158.1

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.
@@ -3,6 +3,7 @@ import {
3
3
  dismissNotificationContract,
4
4
  listNotificationsContract,
5
5
  } from '@cat-factory/contracts'
6
+ import type { ReviewEffort } from '~/types/merge'
6
7
  import type { ApiContext } from './context'
7
8
 
8
9
  /** The human-actionable notification inbox (act / dismiss). */
@@ -12,11 +13,14 @@ export function notificationsApi({ send, ws }: ApiContext) {
12
13
  listNotifications: (workspaceId: string) =>
13
14
  send(listNotificationsContract, { pathPrefix: ws(workspaceId) }),
14
15
 
15
- // Act on a notification (merge the PR / confirm / retry), then resolve it.
16
- actNotification: (workspaceId: string, id: string) =>
16
+ // Act on a notification (merge the PR / confirm / retry), then resolve it. On a merge card,
17
+ // `reviewEffort` records how much review the PR actually needed onto the run's merge track
18
+ // record in the SAME request — always optional (an untagged merge records a null tag).
19
+ actNotification: (workspaceId: string, id: string, reviewEffort?: ReviewEffort | null) =>
17
20
  send(actNotificationContract, {
18
21
  pathPrefix: ws(workspaceId),
19
22
  pathParams: { notificationId: id },
23
+ body: reviewEffort === undefined ? {} : { reviewEffort },
20
24
  }),
21
25
 
22
26
  // Dismiss a notification without acting.
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  createRiskPolicyContract,
3
+ listMergeClassRollupsContract,
4
+ tagMergeReviewEffortContract,
3
5
  createModelPresetContract,
4
6
  deleteRiskPolicyContract,
5
7
  deleteModelPresetContract,
@@ -10,7 +12,7 @@ import {
10
12
  updateRiskPolicyContract,
11
13
  updateModelPresetContract,
12
14
  } from '@cat-factory/contracts'
13
- import type { UpdateRiskPolicyInput } from '~/types/merge'
15
+ import type { ReviewEffort, UpdateRiskPolicyInput } from '~/types/merge'
14
16
  import type { CreateModelPresetInput, UpdateModelPresetInput } from '~/types/model-presets'
15
17
  import type { SendParams } from './client'
16
18
  import type { ApiContext } from './context'
@@ -45,6 +47,24 @@ export function presetsApi({ send, ws }: ApiContext) {
45
47
  reseedRiskPolicy: (workspaceId: string, presetId: string) =>
46
48
  send(reseedRiskPolicyContract, { pathPrefix: ws(workspaceId), pathParams: { presetId } }),
47
49
 
50
+ // ---- merge track record (the per-class evidence behind the policy) -----
51
+ // Every class in ONE request (a single SQL aggregate server-side), so the preset editor can
52
+ // show each class's rule next to the numbers that justify widening it without fanning out.
53
+ listMergeClassRollups: (workspaceId: string) =>
54
+ send(listMergeClassRollupsContract, { pathPrefix: ws(workspaceId) }),
55
+
56
+ // Tag (or clear) how much review a merged PR actually needed.
57
+ tagMergeReviewEffort: (
58
+ workspaceId: string,
59
+ recordId: string,
60
+ reviewEffort: ReviewEffort | null,
61
+ ) =>
62
+ send(tagMergeReviewEffortContract, {
63
+ pathPrefix: ws(workspaceId),
64
+ pathParams: { recordId },
65
+ body: { reviewEffort },
66
+ }),
67
+
48
68
  // ---- model presets (per-task model->agent mapping library) ------------
49
69
  listModelPresets: (workspaceId: string) =>
50
70
  send(listModelPresetsContract, { pathPrefix: ws(workspaceId) }),
@@ -2,6 +2,7 @@ import type { Ref } from 'vue'
2
2
  import type { ExecutionInstance, Pipeline } from '~/types/domain'
3
3
  import type { RequestStepChangesInput } from '@cat-factory/contracts'
4
4
  import type { IterationCapChoice } from '~/types/execution'
5
+ import type { ReviewEffort } from '~/types/merge'
5
6
  import { useWorkspaceStore } from '~/stores/workspace'
6
7
 
7
8
  /**
@@ -125,11 +126,15 @@ export function createExecutionCommands(ctx: ExecutionCommandContext) {
125
126
  })
126
127
  }
127
128
 
128
- /** Merge an open PR (a task in `pr_ready`) — the server completes the task. */
129
- async function mergePr(blockId: string) {
129
+ /**
130
+ * Merge an open PR (a task in `pr_ready`) — the server completes the task. `reviewEffort` records
131
+ * how much review the PR actually needed onto its merge track record in the same request; always
132
+ * optional (an untagged merge records a null tag and nothing downstream breaks).
133
+ */
134
+ async function mergePr(blockId: string, reviewEffort?: ReviewEffort | null) {
130
135
  const ws = useWorkspaceStore()
131
136
  try {
132
- await api.mergeBlock(ws.requireId(), blockId)
137
+ await api.mergeBlock(ws.requireId(), blockId, reviewEffort)
133
138
  await ws.refresh()
134
139
  } catch (e) {
135
140
  runErrors.present(e, 'errors.action.mergeFailed')
@@ -0,0 +1,61 @@
1
+ import { CHANGE_CLASSES, emptyMergeClassRollup } from '@cat-factory/contracts'
2
+ import { defineStore } from 'pinia'
3
+ import { computed, ref } from 'vue'
4
+ import type { ChangeClass, MergeClassRollup, ReviewEffort } from '~/types/merge'
5
+ import { useWorkspaceStore } from '~/stores/workspace'
6
+
7
+ /**
8
+ * The merge track record's per-change-class rollups — the accumulated evidence a workspace widens
9
+ * its per-class auto-merge rules against, plus the reviewer-effort tag surface.
10
+ *
11
+ * Loaded on demand (NOT from the workspace snapshot): the rollups are a settings-screen and
12
+ * merge-card concern, not board state, and they change only when a merge settles. The whole set
13
+ * arrives in ONE request — a single SQL aggregate server-side — so the preset editor never fans
14
+ * out per class.
15
+ */
16
+ export const useMergeTrackRecordsStore = defineStore('mergeTrackRecords', () => {
17
+ const api = useApi()
18
+
19
+ const rollups = ref<MergeClassRollup[]>([])
20
+ const loading = ref(false)
21
+ /** Whether a load has completed at least once, so the UI can tell "empty" from "not yet". */
22
+ const loaded = ref(false)
23
+
24
+ /**
25
+ * Every class keyed for lookup, filled in with zeros for a class the workspace has no records
26
+ * for. The backend already returns the full set; this keeps the UI total even before the first
27
+ * load resolves.
28
+ */
29
+ const byClass = computed<Record<ChangeClass, MergeClassRollup>>(() => {
30
+ const found = new Map(rollups.value.map((r) => [r.changeClass, r]))
31
+ return Object.fromEntries(
32
+ CHANGE_CLASSES.map((c) => [c, found.get(c) ?? emptyMergeClassRollup(c)]),
33
+ ) as Record<ChangeClass, MergeClassRollup>
34
+ })
35
+
36
+ /** Whether the workspace has ANY track record yet (drives the "no data yet" hint). */
37
+ const hasData = computed(() => rollups.value.some((r) => r.total > 0))
38
+
39
+ async function load(): Promise<void> {
40
+ const ws = useWorkspaceStore()
41
+ loading.value = true
42
+ try {
43
+ rollups.value = await api.listMergeClassRollups(ws.requireId())
44
+ loaded.value = true
45
+ } finally {
46
+ loading.value = false
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Tag (or clear) how much review a merged PR needed, then refresh the rollups so the class's
52
+ * effort distribution reflects it immediately.
53
+ */
54
+ async function tag(recordId: string, reviewEffort: ReviewEffort | null): Promise<void> {
55
+ const ws = useWorkspaceStore()
56
+ await api.tagMergeReviewEffort(ws.requireId(), recordId, reviewEffort)
57
+ if (loaded.value) await load()
58
+ }
59
+
60
+ return { rollups, byClass, hasData, loading, loaded, load, tag }
61
+ })
@@ -1,6 +1,7 @@
1
1
  import { defineStore } from 'pinia'
2
2
  import { computed } from 'vue'
3
3
  import type { Notification } from '~/types/domain'
4
+ import type { ReviewEffort } from '~/types/merge'
4
5
  import { useUpsertList } from '~/composables/useUpsertList'
5
6
  import { useWorkspaceStore } from '~/stores/workspace'
6
7
 
@@ -53,10 +54,16 @@ export const useNotificationsStore = defineStore('notifications', () => {
53
54
  /** Total open count, for the toolbar badge. */
54
55
  const count = computed(() => open.value.length)
55
56
 
56
- /** Act on a notification (merge / confirm / retry); the board patches via the event. */
57
- async function act(id: string) {
57
+ /**
58
+ * Act on a notification (merge / confirm / retry); the board patches via the event.
59
+ *
60
+ * `reviewEffort` is the merge card's one-tap "how much review did this need?" answer, recorded
61
+ * onto the run's merge track record in the same request. Always optional: acting without it
62
+ * merges exactly as before and leaves the record's tag null.
63
+ */
64
+ async function act(id: string, reviewEffort?: ReviewEffort | null) {
58
65
  const ws = useWorkspaceStore()
59
- const resolved = await api.actNotification(ws.requireId(), id)
66
+ const resolved = await api.actNotification(ws.requireId(), id, reviewEffort)
60
67
  upsert(resolved)
61
68
  // The action (merge/confirm/retry) changed block/run state — reconcile fully.
62
69
  await ws.refresh()
@@ -6,6 +6,13 @@
6
6
 
7
7
  export type {
8
8
  MergeAssessment,
9
+ // Merge track record — the per-class human evidence behind the auto-merge policy.
10
+ ChangeClass,
11
+ MergeClassRollup,
12
+ MergeClassRule,
13
+ MergeClassRules,
14
+ MergeTrackRecord,
15
+ ReviewEffort,
9
16
  RequirementConcernLevel,
10
17
  RiskPolicy,
11
18
  CreateRiskPolicyInput,
@@ -455,6 +455,19 @@
455
455
  "run": "Trotzdem vorschlagen",
456
456
  "skip": "Überspringen"
457
457
  }
458
+ },
459
+ "classRules": {
460
+ "heading": "Regeln je Änderungskategorie",
461
+ "help": "Jeder Pull Request wird anhand der geänderten Dateien klassifiziert. Eine Kategorie kann immer automatisch zusammengeführt werden, immer ein Review verlangen oder auf die Schwellenwerte oben zurückfallen. Die Zahlen zeigen, was diese Kategorie bisher gebraucht hat.",
462
+ "autoMergeOffWarning": "Für diese Vorlage ist das automatische Zusammenführen aus, daher geht jeder Pull Request weiterhin an einen Menschen. Eine Kategorieregel kann das nicht überschreiben.",
463
+ "noData": "Noch keine Historie",
464
+ "record": "{merged} zusammengeführt, {autoShare} automatisch",
465
+ "frictionless": "{share} ohne Anmerkungen",
466
+ "rule": {
467
+ "thresholds": "Schwellenwerte verwenden",
468
+ "always": "Immer automatisch zusammenführen",
469
+ "never": "Immer Review verlangen"
470
+ }
458
471
  }
459
472
  },
460
473
  "observabilityConnection": {
@@ -1406,7 +1419,9 @@
1406
1419
  "no_rationale": "Der Merger hat den PR bewertet, aber keine Begründung gegeben, daher konnte dem Urteil zum automatischen Mergen nicht vertraut werden; der PR wartet darauf, dass ein Mensch mergt.",
1407
1420
  "no_assessment": "Der Merger hat keine parsbare Bewertung zurückgegeben, daher wartet der PR darauf, dass ein Mensch mergt.",
1408
1421
  "merge_failed": "Die Bewertungen lagen innerhalb der {preset}-Schwellenwerte, aber der automatische Merge konnte nicht abgeschlossen werden (zum Beispiel Branch-Schutz oder ein Konflikt), daher wartet der PR darauf, dass ein Mensch mergt.",
1409
- "merge_partial": "Einige der Pull Requests der Aufgabe wurden gemergt, aber ein späterer nicht, daher wartet die Änderung darauf, dass ein Mensch den Multi-Repo-Merge abschließt oder zurückrollt."
1422
+ "merge_partial": "Einige der Pull Requests der Aufgabe wurden gemergt, aber ein späterer nicht, daher wartet die Änderung darauf, dass ein Mensch den Multi-Repo-Merge abschließt oder zurückrollt.",
1423
+ "class_auto_merge": "Diese Vorlage führt diese Änderungskategorie immer automatisch zusammen, daher wurden die Bewertungen nicht verglichen.",
1424
+ "class_requires_review": "Diese Vorlage gibt diese Änderungskategorie unabhängig von den Bewertungen immer an einen Menschen."
1410
1425
  },
1411
1426
  "scores": "Bewertungen",
1412
1427
  "axis": {
@@ -1818,7 +1833,8 @@
1818
1833
  "fork_decision_pending": "Als gelesen markieren",
1819
1834
  "pr_review_ready": "Als gelesen markieren",
1820
1835
  "budget_paused": "Als gelesen markieren",
1821
- "key_drift": "Veraltete Zugangsdaten entfernen"
1836
+ "key_drift": "Veraltete Zugangsdaten entfernen",
1837
+ "merge_tag_request": "Aufwand erfassen"
1822
1838
  }
1823
1839
  },
1824
1840
  "aiProvidersBanner": {
@@ -4247,7 +4263,8 @@
4247
4263
  "human_test_ready": "Bereit für manuelle Tests",
4248
4264
  "visual_confirmation_ready": "Bereit für visuelle Bestätigung",
4249
4265
  "pr_review_ready": "PR-Review-Befunde",
4250
- "initiative": "Initiativen-Updates"
4266
+ "initiative": "Initiativen-Updates",
4267
+ "merge_tag_request": "Review-Aufwand angefragt"
4251
4268
  },
4252
4269
  "role": {
4253
4270
  "engineering": "Engineering",
@@ -5188,6 +5205,24 @@
5188
5205
  "unlinkSourceFailed": "Quelle konnte nicht getrennt werden"
5189
5206
  }
5190
5207
  },
5208
+ "merge": {
5209
+ "changeClass": {
5210
+ "docs": "Doku & Texte",
5211
+ "test": "Tests",
5212
+ "dependency": "Abhängigkeits-Update",
5213
+ "config": "Konfiguration & CI",
5214
+ "source": "Quellcode",
5215
+ "schema": "Schema & Migrationen",
5216
+ "unknown": "Nicht klassifiziert"
5217
+ },
5218
+ "effort": {
5219
+ "prompt": "Review-Aufwand",
5220
+ "none": "Keine Anmerkungen",
5221
+ "minor": "Kleine Anmerkungen",
5222
+ "major": "Echte Nacharbeit",
5223
+ "classHistory": "{merged} in dieser Kategorie zusammengeführt, {autoShare} automatisch"
5224
+ }
5225
+ },
5191
5226
  "vcs": {
5192
5227
  "panel": {
5193
5228
  "title": "Quellcodeverwaltung",
@@ -1173,7 +1173,9 @@
1173
1173
  "no_rationale": "The merger scored the PR but gave no rationale, so the verdict could not be trusted to auto-merge; the PR is waiting for a human to merge.",
1174
1174
  "no_assessment": "The merger did not return a parseable assessment, so the PR is waiting for a human to merge.",
1175
1175
  "merge_failed": "The scores were within the {preset} thresholds, but the automatic merge could not complete (for example branch protection or a conflict), so the PR is waiting for a human to merge.",
1176
- "merge_partial": "Some of the task's pull requests merged, but a later one could not, so the change is waiting for a human to finish or revert the multi-repo merge."
1176
+ "merge_partial": "Some of the task's pull requests merged, but a later one could not, so the change is waiting for a human to finish or revert the multi-repo merge.",
1177
+ "class_auto_merge": "This preset always auto-merges this class of change, so the scores were not compared.",
1178
+ "class_requires_review": "This preset always sends this class of change to a human, whatever the scores."
1177
1179
  },
1178
1180
  "scores": "Scores",
1179
1181
  "axis": {
@@ -1790,7 +1792,8 @@
1790
1792
  "fork_decision_pending": "Mark read",
1791
1793
  "pr_review_ready": "Mark read",
1792
1794
  "budget_paused": "Mark read",
1793
- "key_drift": "Drop stale credentials"
1795
+ "key_drift": "Drop stale credentials",
1796
+ "merge_tag_request": "Record effort"
1794
1797
  }
1795
1798
  },
1796
1799
  "aiProvidersBanner": {
@@ -2522,6 +2525,25 @@
2522
2525
  "run": "Propose anyway",
2523
2526
  "skip": "Skip"
2524
2527
  }
2528
+ },
2529
+ "classRules": {
2530
+ "heading": "Rules per change class",
2531
+ "help": "Each pull request is classified from the files it changed. A class can always auto-merge, always require review, or fall back to the score ceilings above. The counts show what that class has needed so far.",
2532
+ "autoMergeOffWarning": "Auto-merge is off for this preset, so every pull request still goes to a human. A class rule cannot override that.",
2533
+ "noData": "No history yet",
2534
+ "record": "{merged} merged, {autoShare} automatically",
2535
+ "@record": {
2536
+ "description": "'{autoShare}' is already a formatted percentage; do not add a % sign."
2537
+ },
2538
+ "frictionless": "{share} needed no comments",
2539
+ "@frictionless": {
2540
+ "description": "'{share}' is already a formatted percentage; do not add a % sign."
2541
+ },
2542
+ "rule": {
2543
+ "thresholds": "Use score ceilings",
2544
+ "always": "Always auto-merge",
2545
+ "never": "Always require review"
2546
+ }
2525
2547
  }
2526
2548
  },
2527
2549
  "observabilityConnection": {
@@ -3352,7 +3374,8 @@
3352
3374
  "human_test_ready": "Ready for human testing",
3353
3375
  "visual_confirmation_ready": "Ready for visual confirmation",
3354
3376
  "pr_review_ready": "PR review findings",
3355
- "initiative": "Initiative updates"
3377
+ "initiative": "Initiative updates",
3378
+ "merge_tag_request": "Review-effort tag requested"
3356
3379
  },
3357
3380
  "role": {
3358
3381
  "engineering": "Engineering",
@@ -5317,6 +5340,36 @@
5317
5340
  "unlinkSourceFailed": "Could not unlink source"
5318
5341
  }
5319
5342
  },
5343
+ "merge": {
5344
+ "changeClass": {
5345
+ "docs": "Docs & copy",
5346
+ "test": "Tests",
5347
+ "dependency": "Dependency bump",
5348
+ "@dependency": {
5349
+ "description": "A change that only bumps third-party package versions (a 'dependency bump'), not a change that depends on something."
5350
+ },
5351
+ "config": "Config & CI",
5352
+ "source": "Source code",
5353
+ "@source": {
5354
+ "description": "'Source' here means program source code (as opposed to docs/config/tests), NOT the origin of something."
5355
+ },
5356
+ "schema": "Schema & migrations",
5357
+ "unknown": "Unclassified"
5358
+ },
5359
+ "effort": {
5360
+ "prompt": "Review effort",
5361
+ "none": "No comments",
5362
+ "@none": {
5363
+ "description": "Answer to 'how much review effort did this PR need?': means the reviewer had NOTHING to say, not that no review happened."
5364
+ },
5365
+ "minor": "Minor notes",
5366
+ "major": "Real rework",
5367
+ "classHistory": "{merged} merged in this class, {autoShare} auto-merged",
5368
+ "@classHistory": {
5369
+ "description": "'{autoShare}' is already a formatted percentage; do not add a % sign."
5370
+ }
5371
+ }
5372
+ },
5320
5373
  "vcs": {
5321
5374
  "panel": {
5322
5375
  "title": "Source control",
@@ -1116,7 +1116,9 @@
1116
1116
  "no_rationale": "El fusionador puntuó el PR pero no dio ninguna justificación, así que no se pudo confiar en el veredicto para fusionar automáticamente; el PR espera a que una persona lo fusione.",
1117
1117
  "no_assessment": "El fusionador no devolvió una evaluación analizable, por lo que el PR espera a que una persona lo fusione.",
1118
1118
  "merge_failed": "Las puntuaciones estaban dentro de los umbrales de {preset}, pero la fusión automática no pudo completarse (por ejemplo, protección de rama o un conflicto), por lo que el PR espera a que una persona lo fusione.",
1119
- "merge_partial": "Algunas de las solicitudes de incorporación de la tarea se fusionaron, pero una posterior no pudo, por lo que el cambio espera a que una persona termine o revierta la fusión multirrepositorio."
1119
+ "merge_partial": "Algunas de las solicitudes de incorporación de la tarea se fusionaron, pero una posterior no pudo, por lo que el cambio espera a que una persona termine o revierta la fusión multirrepositorio.",
1120
+ "class_auto_merge": "Este preajuste fusiona siempre esta categoría de cambio de forma automática, así que no se compararon las puntuaciones.",
1121
+ "class_requires_review": "Este preajuste envía siempre esta categoría de cambio a una persona, sean cuales sean las puntuaciones."
1120
1122
  },
1121
1123
  "scores": "Puntuaciones",
1122
1124
  "axis": {
@@ -1721,7 +1723,8 @@
1721
1723
  "fork_decision_pending": "Marcar como leído",
1722
1724
  "pr_review_ready": "Marcar como leída",
1723
1725
  "budget_paused": "Marcar como leída",
1724
- "key_drift": "Descartar credenciales obsoletas"
1726
+ "key_drift": "Descartar credenciales obsoletas",
1727
+ "merge_tag_request": "Registrar esfuerzo"
1725
1728
  },
1726
1729
  "toast": {
1727
1730
  "acted": "Marcado como resuelto",
@@ -2334,6 +2337,19 @@
2334
2337
  "run": "Proponer igualmente",
2335
2338
  "skip": "Omitir"
2336
2339
  }
2340
+ },
2341
+ "classRules": {
2342
+ "heading": "Reglas por categoría de cambio",
2343
+ "help": "Cada pull request se clasifica a partir de los archivos que modificó. Una categoría puede fusionarse siempre de forma automática, exigir siempre revisión, o usar los umbrales de arriba. Los recuentos muestran lo que esa categoría ha necesitado hasta ahora.",
2344
+ "autoMergeOffWarning": "El auto-merge está desactivado en este preajuste, así que cada pull request sigue pasando por una persona. Una regla de categoría no puede anular eso.",
2345
+ "noData": "Aún sin historial",
2346
+ "record": "{merged} fusionados, {autoShare} automáticamente",
2347
+ "frictionless": "{share} no necesitó comentarios",
2348
+ "rule": {
2349
+ "thresholds": "Usar los umbrales",
2350
+ "always": "Fusionar siempre automáticamente",
2351
+ "never": "Exigir siempre revisión"
2352
+ }
2337
2353
  }
2338
2354
  },
2339
2355
  "observabilityConnection": {
@@ -3256,7 +3272,8 @@
3256
3272
  "human_test_ready": "Listo para pruebas humanas",
3257
3273
  "visual_confirmation_ready": "Listo para confirmacion visual",
3258
3274
  "pr_review_ready": "Hallazgos de revisión de PR",
3259
- "initiative": "Actualizaciones de la iniciativa"
3275
+ "initiative": "Actualizaciones de la iniciativa",
3276
+ "merge_tag_request": "Solicitud de esfuerzo de revisión"
3260
3277
  },
3261
3278
  "role": {
3262
3279
  "engineering": "Ingenieria",
@@ -5176,6 +5193,24 @@
5176
5193
  "unlinkSourceFailed": "No se pudo desvincular la fuente"
5177
5194
  }
5178
5195
  },
5196
+ "merge": {
5197
+ "changeClass": {
5198
+ "docs": "Documentación y textos",
5199
+ "test": "Pruebas",
5200
+ "dependency": "Actualización de dependencias",
5201
+ "config": "Configuración y CI",
5202
+ "source": "Código fuente",
5203
+ "schema": "Esquema y migraciones",
5204
+ "unknown": "Sin clasificar"
5205
+ },
5206
+ "effort": {
5207
+ "prompt": "Esfuerzo de revisión",
5208
+ "none": "Sin comentarios",
5209
+ "minor": "Comentarios menores",
5210
+ "major": "Retrabajo real",
5211
+ "classHistory": "{merged} fusionados en esta categoría, {autoShare} de forma automática"
5212
+ }
5213
+ },
5179
5214
  "vcs": {
5180
5215
  "panel": {
5181
5216
  "title": "Control de código fuente",
@@ -1116,7 +1116,9 @@
1116
1116
  "no_rationale": "Le fusionneur a évalué la PR mais n'a donné aucune justification, le verdict n'a donc pas pu être approuvé pour une fusion automatique ; la PR attend une fusion par une personne.",
1117
1117
  "no_assessment": "Le fusionneur n'a pas renvoyé d'évaluation exploitable, la PR attend donc une fusion par une personne.",
1118
1118
  "merge_failed": "Les scores étaient dans les seuils de {preset}, mais la fusion automatique n'a pas pu aboutir (par exemple protection de branche ou conflit), la PR attend donc une fusion par une personne.",
1119
- "merge_partial": "Certaines des pull requests de la tâche ont été fusionnées, mais une suivante n'a pas pu l'être, le changement attend donc qu'une personne termine ou annule la fusion multi-dépôt."
1119
+ "merge_partial": "Certaines des pull requests de la tâche ont été fusionnées, mais une suivante n'a pas pu l'être, le changement attend donc qu'une personne termine ou annule la fusion multi-dépôt.",
1120
+ "class_auto_merge": "Ce préréglage fusionne toujours automatiquement cette catégorie de changement : les scores n’ont donc pas été comparés.",
1121
+ "class_requires_review": "Ce préréglage envoie toujours cette catégorie de changement à un humain, quels que soient les scores."
1120
1122
  },
1121
1123
  "scores": "Scores",
1122
1124
  "axis": {
@@ -1721,7 +1723,8 @@
1721
1723
  "fork_decision_pending": "Marquer comme lu",
1722
1724
  "pr_review_ready": "Marquer comme lu",
1723
1725
  "budget_paused": "Marquer comme lu",
1724
- "key_drift": "Supprimer les identifiants obsolètes"
1726
+ "key_drift": "Supprimer les identifiants obsolètes",
1727
+ "merge_tag_request": "Enregistrer l’effort"
1725
1728
  },
1726
1729
  "toast": {
1727
1730
  "acted": "Marqué comme traité",
@@ -2334,6 +2337,19 @@
2334
2337
  "run": "Proposer quand même",
2335
2338
  "skip": "Ignorer"
2336
2339
  }
2340
+ },
2341
+ "classRules": {
2342
+ "heading": "Règles par catégorie de changement",
2343
+ "help": "Chaque pull request est classée d’après les fichiers qu’elle modifie. Une catégorie peut toujours être fusionnée automatiquement, toujours exiger une revue, ou retomber sur les seuils ci-dessus. Les compteurs montrent ce que cette catégorie a demandé jusqu’ici.",
2344
+ "autoMergeOffWarning": "La fusion automatique est désactivée pour ce préréglage : chaque pull request passe toujours par un humain. Une règle de catégorie ne peut pas outrepasser cela.",
2345
+ "noData": "Pas encore d’historique",
2346
+ "record": "{merged} fusionnés, {autoShare} automatiquement",
2347
+ "frictionless": "{share} sans aucun commentaire",
2348
+ "rule": {
2349
+ "thresholds": "Utiliser les seuils",
2350
+ "always": "Toujours fusionner automatiquement",
2351
+ "never": "Toujours exiger une revue"
2352
+ }
2337
2353
  }
2338
2354
  },
2339
2355
  "observabilityConnection": {
@@ -3256,7 +3272,8 @@
3256
3272
  "human_test_ready": "Pret pour les tests humains",
3257
3273
  "visual_confirmation_ready": "Pret pour la confirmation visuelle",
3258
3274
  "pr_review_ready": "Points de revue de PR",
3259
- "initiative": "Mises a jour de l'initiative"
3275
+ "initiative": "Mises a jour de l'initiative",
3276
+ "merge_tag_request": "Effort de revue demandé"
3260
3277
  },
3261
3278
  "role": {
3262
3279
  "engineering": "Ingenierie",
@@ -5176,6 +5193,24 @@
5176
5193
  "unlinkSourceFailed": "Impossible de dissocier la source"
5177
5194
  }
5178
5195
  },
5196
+ "merge": {
5197
+ "changeClass": {
5198
+ "docs": "Documentation et libellés",
5199
+ "test": "Tests",
5200
+ "dependency": "Mise à jour de dépendances",
5201
+ "config": "Configuration et CI",
5202
+ "source": "Code source",
5203
+ "schema": "Schéma et migrations",
5204
+ "unknown": "Non classé"
5205
+ },
5206
+ "effort": {
5207
+ "prompt": "Effort de revue",
5208
+ "none": "Aucun commentaire",
5209
+ "minor": "Remarques mineures",
5210
+ "major": "Reprise importante",
5211
+ "classHistory": "{merged} fusionnés dans cette catégorie, dont {autoShare} automatiquement"
5212
+ }
5213
+ },
5179
5214
  "vcs": {
5180
5215
  "panel": {
5181
5216
  "title": "Gestion de code source",
@@ -1116,7 +1116,9 @@
1116
1116
  "no_rationale": "הממזג נתן ציון ל-PR אך לא סיפק נימוק, ולכן לא ניתן היה לסמוך על ההכרעה למיזוג אוטומטי; ה-PR ממתין למיזוג ידני.",
1117
1117
  "no_assessment": "הממזג לא החזיר הערכה שניתן לפענח, ולכן ה-PR ממתין למיזוג ידני.",
1118
1118
  "merge_failed": "הציונים היו בתוך ספי {preset}, אך המיזוג האוטומטי לא הושלם (למשל הגנת ענף או התנגשות), ולכן ה-PR ממתין למיזוג ידני.",
1119
- "merge_partial": "חלק מבקשות המשיכה של המשימה מוזגו, אך אחת מאוחרת יותר נכשלה, ולכן השינוי ממתין שאדם ישלים או יבטל את המיזוג הרב-מאגרי."
1119
+ "merge_partial": "חלק מבקשות המשיכה של המשימה מוזגו, אך אחת מאוחרת יותר נכשלה, ולכן השינוי ממתין שאדם ישלים או יבטל את המיזוג הרב-מאגרי.",
1120
+ "class_auto_merge": "ההגדרה הזאת ממזגת תמיד אוטומטית שינויים מהסוג הזה, ולכן הניקוד לא הושווה.",
1121
+ "class_requires_review": "ההגדרה הזאת מעבירה תמיד שינויים מהסוג הזה לאדם, בלי קשר לניקוד."
1120
1122
  },
1121
1123
  "scores": "ציונים",
1122
1124
  "axis": {
@@ -1721,7 +1723,8 @@
1721
1723
  "fork_decision_pending": "סמן כנקרא",
1722
1724
  "pr_review_ready": "סמן כנקרא",
1723
1725
  "budget_paused": "סמן כנקרא",
1724
- "key_drift": "מחק אישורים מיושנים"
1726
+ "key_drift": "מחק אישורים מיושנים",
1727
+ "merge_tag_request": "לתעד את המאמץ"
1725
1728
  },
1726
1729
  "toast": {
1727
1730
  "acted": "סומן כטופל",
@@ -2455,6 +2458,19 @@
2455
2458
  "run": "הצע בכל זאת",
2456
2459
  "skip": "דלג"
2457
2460
  }
2461
+ },
2462
+ "classRules": {
2463
+ "heading": "כללים לפי סוג השינוי",
2464
+ "help": "כל בקשת מיזוג מסווגת לפי הקבצים שהיא שינתה. קטגוריה יכולה להתמזג תמיד אוטומטית, לדרוש תמיד סקירה, או לחזור לסף הניקוד שלמעלה. המספרים מראים מה הקטגוריה הזאת דרשה עד כה.",
2465
+ "autoMergeOffWarning": "המיזוג האוטומטי כבוי בהגדרה הזאת, ולכן כל בקשת מיזוג עוברת לאדם. כלל של קטגוריה לא יכול לעקוף את זה.",
2466
+ "noData": "אין עוד היסטוריה",
2467
+ "record": "{merged} מוזגו, {autoShare} אוטומטית",
2468
+ "frictionless": "{share} לא דרשו הערות",
2469
+ "rule": {
2470
+ "thresholds": "לפי סף הניקוד",
2471
+ "always": "למזג תמיד אוטומטית",
2472
+ "never": "לדרוש תמיד סקירה"
2473
+ }
2458
2474
  }
2459
2475
  },
2460
2476
  "observabilityConnection": {
@@ -3267,7 +3283,8 @@
3267
3283
  "human_test_ready": "מוכן לבדיקה אנושית",
3268
3284
  "visual_confirmation_ready": "מוכן לאישור חזותי",
3269
3285
  "pr_review_ready": "ממצאי בדיקת PR",
3270
- "initiative": "עדכוני יוזמה"
3286
+ "initiative": "עדכוני יוזמה",
3287
+ "merge_tag_request": "בקשה לתיוג מאמץ הסקירה"
3271
3288
  },
3272
3289
  "role": {
3273
3290
  "engineering": "הנדסה",
@@ -5187,6 +5204,24 @@
5187
5204
  "unlinkSourceFailed": "לא ניתן לבטל את קישור המקור"
5188
5205
  }
5189
5206
  },
5207
+ "merge": {
5208
+ "changeClass": {
5209
+ "docs": "תיעוד וטקסטים",
5210
+ "test": "בדיקות",
5211
+ "dependency": "עדכון תלויות",
5212
+ "config": "תצורה ו-CI",
5213
+ "source": "קוד מקור",
5214
+ "schema": "סכמה והגירות",
5215
+ "unknown": "לא מסווג"
5216
+ },
5217
+ "effort": {
5218
+ "prompt": "מאמץ הסקירה",
5219
+ "none": "בלי הערות",
5220
+ "minor": "הערות קטנות",
5221
+ "major": "עבודה מחדש משמעותית",
5222
+ "classHistory": "{merged} מוזגו בקטגוריה הזאת, {autoShare} מוזגו אוטומטית"
5223
+ }
5224
+ },
5190
5225
  "vcs": {
5191
5226
  "panel": {
5192
5227
  "title": "ניהול קוד מקור",