---
title: "Richieste di modifica"
description: "Come il lavoro svolto nelle sessioni raggiunge il branch predefinito tramite revisione."
---

Una richiesta di modifica (CR) unisce un branch git a un altro. Beeuni crea una CR dal branch della sessione (`head_ref`) al branch predefinito del progetto (`base_ref`, di solito `main`). La riga della CR contiene metadati; l'unione, il diff e i controlli dei conflitti vengono eseguiti come vere operazioni git sul repository del progetto. Una CR è l'unico modo in cui il lavoro di una sessione arriva al branch predefinito.

<a id="why-work-goes-through-a-cr"></a>

## Perché il lavoro passa da una CR

Una sessione viene eseguita in una sandbox sul proprio branch, che prende il nome dall'ID della sessione. La sandbox non dura per sempre, ma il branch sì: git è l'unica registrazione durevole del lavoro di una sessione. Ogni nuova sessione parte dal branch predefinito. Finché una CR non viene unita, il lavoro resta sul proprio branch, senza revisione e invisibile a tutti gli altri agenti, trigger e collaboratori. Vale per ogni modifica: codice, agenti, skill e manifest (`beeuni.yaml`) — nesbeeuni eccezione.

<a id="the-agent-mandate"></a>

## Il mandato dell'agente

Per applicare qualsiasi modifica al branch predefinito del progetto, un agente deve aprire una CR. L'agente non unisce la propria CR: la decisione spetta all'utente. Segui queste regole:

1. Esegui commit sul branch della sessione (`$BEEUNI_BRANCH_NAME`). Crea commit piccoli e funzionanti. Non riscrivere la cronologia né eseguire push forzati.
2. Esegui il push del branch: `git push origin HEAD`.
3. Apri la CR: `beeuni cr open --title "..." --description "..."`. Nella sandbox di una sessione, `--head` e `--session` hanno come valore predefinito `$BEEUNI_BRANCH_NAME` e `$BEEUNI_SESSION_ID`. `--base` ha come valore predefinito il branch predefinito del progetto.
4. Comunica all'utente il numero della CR, così che possa esaminarla.
5. Fermati. Non unire la CR personalmente.

<a id="anti-patterns"></a>

### Pratiche da evitare

- **Eseguire un push forzato sul branch predefinito.** Viola il processo di revisione, anche se il backend lo consente.
- **«È sul mio branch, prendilo tu.»** Il branch della sessione scompare quando la sandbox si arresta, a meno che nel frattempo una CR non lo abbia unito.
- **Inviare la modifica come file, testo incollato o archivio.** Il sistema delle CR risolve già questo problema.

<a id="data-model"></a>

## Modello dei dati

Le CR risiedono nella tabella `change_requests`.

| Colonna | Tipo | Note |
| --- | --- | --- |
| `cr_id` | uuid | Chiave primaria. Identificatore dell'API REST. |
| `project_id` | uuid | Progetto a cui appartiene la CR. |
| `number` | integer | Numero visualizzato nel progetto (`#1`, `#2`…). Univoco per progetto. Non viene mai riutilizzato. |
| `title` | text | Obbligatorio. |
| `description` | text | Per impostazione predefinita è una stringa vuota. |
| `base_ref` | text | Branch in cui viene eseguita l'unione. Di solito `main`. |
| `head_ref` | text | Branch da cui viene eseguita l'unione. In una sessione, è l'ID della sessione (un UUID). |
| `status` | enum | `open`, `merged` o `closed`. |
| `head_commit_sha` | text | Per le CR aperte, viene aggiornato a ogni lettura in base alla punta live di `head_ref`. Per le CR unite, viene acquisito al momento dell'unione. |
| `base_commit_sha` | text | Stessa regola, per `base_ref`. |
| `origin_session_id` | text | Sessione che ha aperto la CR. Viene impostato su null se la sessione viene eliminata. |
| `created_by` | uuid | Utente che ha creato la CR. |
| `merged_at` / `merged_by` | timestamp / uuid | Quando e chi ha unito la CR. |
| `merge_commit_sha` | text | Commit di unione. In caso di fast-forward, è uguale a `head_commit_sha`. |
| `closed_at` / `closed_by` | timestamp / uuid | Quando e chi ha chiuso la CR senza unirla. |
| `metadata` | jsonb | Contiene `requested_changes`, un elenco di voci `{text, by, at}` aggiunte da `POST /:crId/request-changes`. Le CR non hanno una tabella separata per i commenti. |
| `created_at` / `updated_at` | timestamp | Impostato alla creazione. Aggiornato a ogni cambio di stato o aggiornamento degli SHA. |

Un indice univoco su `(project_id, number)` consente di fare riferimento a una CR tramite il suo numero breve anziché il suo UUID.

<a id="lifecycle"></a>

## Ciclo di vita

```
open ──(merge)──▶ merged      (terminal)
open ──(close)──▶ closed ──(reopen)──▶ open
```

- `open` è lo stato iniziale.
- `closed` è reversibile. `POST /:crId/reopen` lo riporta a `open`.
- `merged` è terminale. Non è possibile riaprire o chiudere una CR unita. Apri una nuova CR sullo stato risultante dall'unione.

Beeuni rifiuta di creare una CR se il branch non contiene commit in harness sperimentaleù rispetto al branch predefinito. Di solito significa che l'agente ha eseguito il commit in locale ma non ha mai fatto il push. Esegui il push dei commit e poi crea di nuovo la CR.

<a id="sha-refresh"></a>

## Aggiornamento degli SHA

Per una CR aperta, Beeuni aggiorna `head_commit_sha` e `base_commit_sha` in base ai branch live a ogni `GET`. Se il repository è irraggiungibile o manca un branch, Beeuni salta l'aggiornamento e restituisce gli ultimi metadati noti della CR. Una CR unita conserva gli SHA acquisiti al momento dell'unione: Beeuni non li aggiorna harness sperimentaleù.

<a id="merge-mechanics"></a>

## Meccanismi di unione

`POST /v1/projects/:projectId/change-requests/:crId/merge` esegue questi passaggi.

1. Beeuni legge il manifest (`beeuni.yaml`) da `head_ref` e lo convalida rispetto allo schema del manifest. Un branch senza manifest supera il controllo. Un manifest non valido restituisce `422` con `code: "MANIFEST_INVALID"` e interrompe l'unione.
2. Beeuni esegue il fast-forward di `base_ref` se `head_ref` è strettamente harness sperimentaleù avanti.
3. Altrimenti, Beeuni crea un commit di unione. Il messaggio predefinito è `Merge CR #<n>: <title>`; puoi cambiarlo con `message` nel corpo della richiesta. L'autore del commit è `Beeuni <noreply@beeuni.com>`.
4. In caso di conflitto, viene restituito `409` con l'elenco dei conflitti. Prima dell'unione, puoi controllare lo stesso elenco con `GET /:crId/merge-preview`.
5. In caso di esito positivo, Beeuni imposta `status` su `merged`, registra `merged_at`, `merged_by` e `merge_commit_sha`, e invalida la cache git del progetto.

Se la CR non è `open`, l'unione restituisce `409`.

<a id="merge-preview"></a>

### Anteprima dell'unione

`GET /:crId/merge-preview` restituisce:

| Campo | Tipo | Significato |
| --- | --- | --- |
| `base_sha` | string | Punta corrente di `base_ref`. |
| `head_sha` | string | Punta corrente di `head_ref`. |
| `merge_base` | string \| null | Antenato comune. Null se le cronologie non sono correlate. |
| `is_up_to_date` | boolean | `head_ref` è stato unito completamente a `base_ref`. |
| `can_merge` | boolean | Nessun conflitto. |
| `can_fast_forward` | boolean | `head_ref` è strettamente harness sperimentaleù avanti di `base_ref`. |
| `conflicts` | string[] | Percorsi dei file che genererebbero conflitti. |

<a id="rest-api"></a>

## API REST

Tutte le route si trovano sotto `/v1/projects/:projectId/change-requests`.

| Metodo | Percorso | Note |
| --- | --- | --- |
| GET | `/` | `?status=open\|merged\|closed\|all`. Senza filtro, restituisce tutti gli stati. |
| POST | `/` | Corpo: `{title, description?, head_ref, base_ref?, session_id?}`. Restituisce `201`. |
| GET | `/:crId` | Restituisce la CR. Aggiorna gli SHA come effetto collaterale. |
| PATCH | `/:crId` | Modifica `title` o `description`. `409` se non è `open`. |
| GET | `/:crId/diff` | Patch unificata: elenco dei file, aggiunte, eliminazioni. |
| GET | `/:crId/merge-preview` | Vedi Anteprima dell'unione sopra. |
| POST | `/:crId/merge` | Corpo: `{message?}`. `422` in caso di manifest non valido. `409` in caso di conflitto o se non è `open`. |
| POST | `/:crId/close` | `409` se è già `merged`. |
| POST | `/:crId/reopen` | `409` se non è `closed`. |
| POST | `/:crId/request-changes` | Corpo: `{feedback}`. Aggiunge a `metadata.requested_changes` e riattiva l'agente della sessione di origine. `409` se non è `open`. |

`POST /` rifiuta un `head_ref` che non contiene commit in harness sperimentaleù rispetto a `base_ref`: `422 code: "CR_HEAD_NOT_AHEAD"`. È l'errore che vede un agente se apre una CR prima di eseguire il push del branch.

<a id="authorization"></a>

### Autorizzazioni

Le route di lettura richiedono l'accesso in lettura al progetto. Le route di scrittura richiedono l'accesso in scrittura. Ogni azione di scrittura richiede anche una capability, indicata di seguito per un token completo e per il token con ambito limitato di una sessione.

| Azione | Capability |
| --- | --- |
| Aprire una CR | `project.gitops.push` |
| Richiedere modifiche | `project.review.act` |
| Unire | `project.gitops.merge` |

Una capability per ogni azione, sia per un token completo sia per il token con ambito limitato di una sessione. Apertura e unione sono permessi distinti: un token può aprire richieste di modifica senza poterle unire. È questo il meccanismo alla base del mandato dell'agente descritto sopra.

`project.cr.open` e `project.cr.merge` erano i nomi precedenti al passaggio per `project.gitops.push` e `project.gitops.merge`, la stessa capability con un secondo nome. Un `beeuni.yaml` che ne elenca ancora uno continua a funzionare (quando viene risolto, il grant viene riscritto usando la dicitura corrente), ma per ogni nuovo elemento usa il nome `gitops`.

Una sessione non può mai unire una richiesta di modifica che ha aperto lei stessa, indipendentemente dai permessi ricevuti. Questa regola è strutturale, non è una capability.
