---
name: wellknown_oidc_patch
kind: function
lang: go
domain: infra
version: "0.1.0"
purity: impure
signature: "func WellknownOidcPatch(cfg WellknownOidcPatchConfig) (WellknownOidcPatchResult, error)"
description: "Parchea el JSON .well-known/matrix/client aniadiendo org.matrix.msc2965.authentication (MAS issuer + account URL) para que los clientes Matrix descubran el OIDC provider dinamicamente. Preserva todos los campos existentes (m.homeserver, org.matrix.msc4143.rtc_foci, etc.). Crea backup antes de escribir. Soporta DryRun."
tags: ["matrix", "mas", "oidc", "well-known", "msc2965", "migration", "mas-migration", "infra", "matrix-mas"]
uses_functions: []
uses_types: ["error_go_core"]
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["encoding/json", "fmt", "os", "path/filepath", "time"]
tested: true
tests:
  - "patch adds key and preserves existing fields"
  - "idempotent: second call returns Modified=false"
  - "dry run does not write file"
  - "nonexistent file returns error"
test_file_path: "functions/infra/wellknown_oidc_patch_test.go"
file_path: "functions/infra/wellknown_oidc_patch.go"
params:
  - name: WellknownJsonPath
    desc: "Ruta absoluta al archivo .well-known/matrix/client JSON (copiado del VPS antes de llamar; el operador copia de vuelta tras la llamada)"
  - name: Issuer
    desc: "URL del MAS issuer, DEBE terminar en '/' (RFC 8414). Ej: https://auth-af2f3d.organic-machine.com/"
  - name: AccountURL
    desc: "URL del account page del MAS. Ej: https://auth-af2f3d.organic-machine.com/account"
  - name: BackupDir
    desc: "Directorio donde se escribe wellknown_<unix_ts>.json antes de modificar. Se crea con mkdir -p si no existe."
  - name: DryRun
    desc: "Si true, calcula Before/After y Modified pero no escribe ningun archivo ni crea backup."
output: "WellknownOidcPatchResult con BackupPath (vacio en DryRun/no-op), Before y After JSON pretty-printed, y Modified=false si el valor ya era identico."
---

## Ejemplo

```go
cfg := infra.WellknownOidcPatchConfig{
    WellknownJsonPath: "/tmp/wellknown_client.json",
    Issuer:            "https://auth-af2f3d.organic-machine.com/",
    AccountURL:        "https://auth-af2f3d.organic-machine.com/account",
    BackupDir:         "/tmp/wellknown_backups",
    DryRun:            true,
}
res, err := infra.WellknownOidcPatch(cfg)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Modified:", res.Modified)
fmt.Println("After:\n", res.After)

// Si el resultado es correcto, volver a llamar con DryRun: false para escribir.
```

## Cuando usarla

Paso 5 de la migracion 0162 (Synapse → MAS): antes de hacer hot-reload nginx del container `wellknown`. Tambien util si cambia el issuer MAS en el futuro (basta llamarla de nuevo con el nuevo URL — la idempotencia garantiza que no duplica la clave).

## Gotchas

- **Issuer DEBE terminar en `/`**: los clientes Matrix siguen RFC 8414 estrictamente. Un issuer sin `/` final causa fallos de descubrimiento silenciosos.
- **Usar mapa dinamico, no struct**: la funcion parsea el JSON en `map[string]any` para preservar campos desconocidos. No asumir que el archivo solo tiene `m.homeserver`.
- **Tras escribir, recargar nginx**: `ssh <host> docker exec <wellknown_container> nginx -s reload`. Esta funcion no lo hace — es responsabilidad del operador.
- **Synapse tambien puede servir el well-known**: `/_matrix/client/.well-known` puede provenir de Synapse ademas del container wellknown. Verificar con `curl -s https://matrix.organic-machine.com/.well-known/matrix/client` y `curl -s https://matrix.organic-machine.com/_matrix/client/.well-known/matrix/client` para saber cual usa cada cliente.
- **DryRun no crea backup ni BackupDir**: usar DryRun para verificar el diff antes de ejecutar en produccion.
