Skip to content

Merge develop into main: GT-603 agent turn ledger - #83

Merged
beyondnetPeru merged 4 commits into
mainfrom
develop
Aug 1, 2026
Merged

Merge develop into main: GT-603 agent turn ledger#83
beyondnetPeru merged 4 commits into
mainfrom
develop

Conversation

@beyondnetPeru

Copy link
Copy Markdown
Contributor

Promotes develop to main after the branch-hygiene pass on this satellite.

What lands

#81 — GT-603: the audit ledger can say whether a human or an agent acted. /assistant/converse was the only path a non-human executor touched a customer's corpus through, and it persisted nothing — so the product's differentiating claim was false in code. The turn now goes through IAgentExecutionPort, which checks the scope, seats the entry and only then lets the runtime act.

Two commits were added on top to get the PR mergeable:

  • The RoboSoft E2E asserted a runtime this deployment never installs. Deploy check (kind + Helm + smoke) was the branch's only red job and its only red assertion was POST /assistant/converse responds 2xx — status 502. Every ledger assertion around it passed. The chart wires AgentRuntime__BaseUrl to evolith-agent-runtime, a service the kind smoke does not install, so the proxy leg fails while the seating succeeds. The check now asserts what the deployment can answer for — that the turn was seated — and stays red on 4xx (scope or attribution refused) or 503 (the ledger refused the entry). Not fixed with MockFallback: that would green the ledger assertions against a stub, and smoke-app.sh pins CoreApi__MockFallback=false for the same reason.
  • Merge conflict with GT-616, resolved keeping both. The PR was DIRTY, which is why GitHub ran no checks at all on it. While the branch was open, develop landed GT-616 and put a governance trace on this same endpoint — over the old gateway.ConverseAsync path that GT-603 replaces. Keeping either side alone lost something real. The trace now wraps the port, not the gateway: the turn is seated before the runtime acts, so a span starting later would miss the only leg that can refuse it. All three exits are tagged, with the port's failure tagged untranslated so AgentExecution.NotAuditable and AgentRuntime.Failed stay distinguishable in traces even though both leave as 5xx.

Known red check, pre-existing on this trunk

conform fails, and it fails on develop and main too — since 97916eb ("close contract and capability parity gaps"), which made the Core checkout mandatory and hard-fails with exit 1 when CORE_REPO_TOKEN is absent. That secret is not configured on this repository, so every run since 2026-08-01T08:29 is red. It is unrelated to #81 and this merge neither causes nor worsens it.

Branch hygiene in the same pass

feat/eag-01-consume-ums-sdk deleted: its premise is blocked upstream (T-040 — the Ums.Sdk.* packages are unpublished, 404 on nuget.org), its merge into develop was reverted twice (7d5eed2, bc20da1), and the substance of EAG-01 is now carried by ADR T-053, whose interim HS256 path is already implemented on develop.

🤖 Generated with Claude Code

beyondnetPeru and others added 4 commits July 30, 2026 21:25
…ico (GT-603)

El ledger de turnos agénticos estaba escrito, probado y SIN REGISTRAR:
`IAgentExecutionPort` no aparecía en ningún contenedor ni en ningún endpoint, y
`/assistant/converse` —la única vía por la que un agente tocaba el corpus de un
cliente— proxyaba al runtime sin persistir nada. La afirmación diferencial del
producto (distinguir un acto humano de uno agéntico en el expediente) era falsa
en el código.

Y era la ficha que CADUCA: `audit_entries` es append-only por trigger desde
COH-014, así que toda fila escrita antes de que existiera el discriminador queda
inatribuible para siempre — el UPDATE que la tiparía está prohibido por la base.

- `AuditActor`/`AuditActorType`: human | agent | system, más `unknown` reservado
  a lo anterior a la migración y EXCLUIDO de toda ruta de escritura.
- `AuditEntry.Create` exige la atribución como parámetro obligatorio: los 8
  sitios que escriben en el expediente declaran ahora quién escribe. Se añade
  `Rehydrate` para poder LEER `unknown` sin poder escribirlo.
- Migración `AddAuditActorAttribution`: `actor_type` NOT NULL + `agent_id`,
  `model_id`, `session_id`. El DEFAULT `'unknown'` vive sólo dentro del
  `ADD COLUMN` (fast default: sin reescritura, sin disparar el trigger) y se
  RETIRA acto seguido, para que ninguna fila nueva entre sin declarar su actor.
  Los tres triggers append-only quedan intactos.
- `AssistantEndpoints` pasa por el puerto: scope comprobado, turno asentado y
  sólo entonces se deja actuar al runtime. La respuesta se devuelve intacta.
- `AgentTurnAuditor` CONFIRMA la escritura (`SaveEntitiesAsync`): sin ella, «el
  turno se pudo registrar» era una afirmación sobre memoria que nadie persistía.
- Un turno sin identidad de agente se rechaza: no es atribuible, y en un registro
  que no admite corrección es preferible no escribirlo a escribirlo mal.
- `audit-trail.robot.mjs` verifica extremo a extremo, contra la API viva, que un
  turno agéntico aterriza tipado como `agent` con su agente identificado y que un
  acto humano en el MISMO expediente sigue diciendo `human`.

Verificado: 1034 pruebas + 14 de arquitectura en verde; las pruebas vivas de
esquema contra PostgreSQL real (EVOLITH_CORE_LIVE=1) y RoboSoft `audit-trail`
25/25 contra tracker-api en marcha.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ment never installs

`Deploy check (kind + Helm + smoke)` was the only red job on this branch, and the
only red assertion in it was `POST /assistant/converse responds 2xx` — status 502.
Every ledger assertion around it passed: the turn is in the trail, typed `agent`,
with the acting agent identified, the human principal preserved, the scope declared
and the prompt absent.

That is not a flake and not a regression. `AssistantEndpoints` seats the turn through
`IAgentExecutionPort` BEFORE the runtime is allowed to act, then proxies; the chart
wires `AgentRuntime__BaseUrl` to `evolith-agent-runtime`, a service the kind smoke
does not install, so the proxy leg returns 502 `AgentRuntime.Failed` while the
seating — the thing this scenario exists to prove — succeeds.

So the check asserted the availability of an absent dependency. It now asserts what
the deployment can actually answer for: the turn was seated. 2xx when a runtime
replies, 502 when none is deployed, and still red on 4xx (scope or attribution
refused, no turn seated) or 503 (`AgentExecution.NotAuditable` / `AgentTurnAuditor.*`
— the ledger refused the entry).

Not fixed by enabling `MockFallback`: that would turn the ledger assertions green
against a stub reply. `smoke-app.sh` pins `CoreApi__MockFallback=false` for the same
reason. Installing the runtime in the smoke environment is the real closure and
belongs with the deployment, not with this gap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…za (GT-616) y ledger (GT-603)

El PR estaba DIRTY, y por eso GitHub no ejecutaba ni un check: no podía calcular
el merge. El conflicto es real, no textual. Mientras esta rama estaba abierta,
`develop` recibió GT-616 y le puso una traza de gobernanza al mismo endpoint —
pero sobre la vía ANTIGUA, `gateway.ConverseAsync`, que es exactamente la que
GT-603 sustituye por `IAgentExecutionPort`.

Quedarse con un lado perdía algo real: el de develop, el asiento en el expediente;
el de la rama, la traza. Se conservan los dos.

La traza envuelve al PUERTO, no al gateway. Desde GT-603 el turno se asienta antes
de que el runtime actúe, así que una traza que empezara después no vería el único
tramo capaz de rechazar el turno — que es el que hay que poder buscar.

Las tres salidas quedan etiquetadas: `ex.Code` en el rechazo de perímetro,
`resultado.Error` SIN traducir cuando falla el puerto, y `ok` en el éxito. El error
sin traducir es deliberado: `AgentExecution.NotAuditable` y `AgentRuntime.Failed`
salen ambos como 5xx, pero en la traza son dos historias distintas —el expediente
rechazó el asiento, o el runtime no respondió— y colapsarlas al código HTTP borraría
justo la que hay que poder distinguir.

Verificado: `Tracker.Presentation` compila con 0 avisos y 245 tests de
Assistant/AgentExecution/Tracing/Governance en verde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GT-603: the audit ledger can finally say whether a human or an agent did it
@beyondnetPeru
beyondnetPeru merged commit d04737d into main Aug 1, 2026
8 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant