d83ad87151
SharedKernel:
- ActionRisk (risk lives on the action) + GatePolicy (the pure autonomy x risk matrix:
Read never holds, Draft/Publish hold unless Autonomous, Destructive ALWAYS holds).
- IActionGate (AgentActionProposal -> execute|hold) and IBoardWriter.AttachArtifactAsync.
Governance:
- ReviewItem (held action: artifact, child titles, trace, decision, edit distance) in a new
review_items table (AddReviewItems migration).
- ActionGate: hold -> ReviewItem + "action.held" audit; autonomous -> execute + audit.
- HeldActionExecutor: writes the artifact onto the task and creates the child tasks via
IBoardWriter (implemented by OrgBoard — no cross-module table access).
- Review inbox API: GET /api/governance/reviews (scope-filtered to where the caller may
approve), POST /reviews/{id}/approve (optional edited content/children -> normalized
edit distance recorded — the north-star metric), POST /reviews/{id}/sendback. Deciding
twice is 409; Members are 403.
Assembler:
- OutputParser (numbered-list child titles, conservative) and the executor now hands every
completed run's proposal to the gate.
OrgBoard: WorkItem.AttachArtifact + BoardWriter.AttachArtifactAsync.
Verified: build green; ArchitectureTests 8/8; IntegrationTests 41/41 incl. the full M5
acceptance — Aria (gated) proposes a spec, it waits in the inbox with its trace, a Member is
403'd, the owner edits-and-approves, the spec + four child stories land on the board, edit
distance > 0 is recorded and audited; Quill (autonomous) executes straight to the board;
destructive holds even for an autonomous seat and can be sent back. Plus the GatePolicy matrix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
5.2 KiB
C#
151 lines
5.2 KiB
C#
// <auto-generated />
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
using TeamUp.Modules.Governance.Persistence;
|
|
|
|
#nullable disable
|
|
|
|
namespace TeamUp.Modules.Governance.Persistence.Migrations
|
|
{
|
|
[DbContext(typeof(GovernanceDbContext))]
|
|
[Migration("20260610041006_AddReviewItems")]
|
|
partial class AddReviewItems
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
{
|
|
#pragma warning disable 612, 618
|
|
modelBuilder
|
|
.HasDefaultSchema("governance")
|
|
.HasAnnotation("ProductVersion", "10.0.8")
|
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
|
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
|
|
modelBuilder.Entity("TeamUp.Modules.Governance.Domain.AuditEntry", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Action")
|
|
.IsRequired()
|
|
.HasMaxLength(100)
|
|
.HasColumnType("character varying(100)");
|
|
|
|
b.Property<Guid?>("ActorMemberId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Details")
|
|
.HasMaxLength(2000)
|
|
.HasColumnType("character varying(2000)");
|
|
|
|
b.Property<Guid>("EntityId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("EntityType")
|
|
.IsRequired()
|
|
.HasMaxLength(100)
|
|
.HasColumnType("character varying(100)");
|
|
|
|
b.Property<DateTimeOffset>("OccurredAtUtc")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("OccurredAtUtc");
|
|
|
|
b.HasIndex("EntityType", "EntityId");
|
|
|
|
b.ToTable("audit_entries", "governance");
|
|
});
|
|
|
|
modelBuilder.Entity("TeamUp.Modules.Governance.Domain.ReviewItem", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("ActionKind")
|
|
.IsRequired()
|
|
.HasMaxLength(60)
|
|
.HasColumnType("character varying(60)");
|
|
|
|
b.Property<Guid>("AgentId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<Guid>("AgentRunId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.PrimitiveCollection<List<string>>("ChildTitles")
|
|
.IsRequired()
|
|
.HasColumnType("text[]");
|
|
|
|
b.Property<string>("Content")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTimeOffset>("CreatedAtUtc")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<DateTimeOffset?>("DecidedAtUtc")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid?>("DecidedByMemberId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Decision")
|
|
.HasMaxLength(30)
|
|
.HasColumnType("character varying(30)");
|
|
|
|
b.Property<double?>("EditDistance")
|
|
.HasColumnType("double precision");
|
|
|
|
b.Property<Guid>("OrganizationId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Risk")
|
|
.IsRequired()
|
|
.HasMaxLength(20)
|
|
.HasColumnType("character varying(20)");
|
|
|
|
b.Property<Guid>("SeatId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Status")
|
|
.IsRequired()
|
|
.HasMaxLength(20)
|
|
.HasColumnType("character varying(20)");
|
|
|
|
b.Property<Guid>("TeamId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Title")
|
|
.IsRequired()
|
|
.HasMaxLength(300)
|
|
.HasColumnType("character varying(300)");
|
|
|
|
b.Property<string>("Trace")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<Guid>("WorkItemId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("AgentRunId");
|
|
|
|
b.HasIndex("OrganizationId", "Status");
|
|
|
|
b.ToTable("review_items", "governance");
|
|
});
|
|
#pragma warning restore 612, 618
|
|
}
|
|
}
|
|
}
|