/** * The responsibility matrix (#557, ADR 0159): RACI over the model, derived * the way the RTM is derived and never authored. Rows are subjects; columns * are the people the model holds; a cell is the letters one person carries * on one row, each letter with the claim that put it there. * * Accountable is the `yarramate/ownership/owner` claim. Responsible, * Consulted and Informed are the three `yarramate/policy@0.2` relationship * kinds, read through the lineage so a profile's own subkind counts. A * person named as `by` on an attestation of a subject was consulted on it: * derived into the cell with the topic and the date, never written back as * an edge, and never counted toward a gap. * * Deterministic: identical inputs give identical bytes, so CI can diff it. */ import type { ResolvedProfileContext, SemanticGraph } from './compiler.js'; import { type ResponsibilityLetter } from './responsibility-kinds.js'; export type RaciLetter = 'A' | ResponsibilityLetter; /** Where a letter came from: an authored line a reader can open. */ export interface ResponsibilitySource { readonly path: string; readonly line: number; } export type ResponsibilityCellSource = { readonly kind: 'owner'; readonly source: ResponsibilitySource; } | { readonly kind: 'relationship'; readonly relationship: string; readonly relationshipKind: string; readonly source: ResponsibilitySource; } | { readonly kind: 'attestation'; readonly topic: string; readonly on: string; readonly source: ResponsibilitySource; }; export interface ResponsibilityCell { /** In A, R, C, I order, each at most once. */ readonly letters: readonly RaciLetter[]; readonly sources: readonly ResponsibilityCellSource[]; } export interface ResponsibilityPerson { readonly id: string; readonly name: string; readonly kind: string; /** * Whether something serves this person. A served actor with no letter is * a consumer, not a responsibility holder; `idle` carries the flag so a * renderer can leave consumers out. */ readonly served: boolean; } export interface ResponsibilityRow { readonly subject: string; readonly name: string; readonly kind: string; /** By person id; only people with a letter on this row appear. */ readonly cells: Readonly>; } export interface ResponsibilityMatrix { readonly format: 'yarramate/responsibility/v1'; readonly workspace: string; /** The projection the rows came from, when they came from one. */ readonly projection?: string; readonly summary: { readonly rows: number; readonly people: number; readonly cells: number; readonly noAccountable: number; readonly noResponsible: number; readonly idle: number; }; readonly people: readonly ResponsibilityPerson[]; readonly rows: readonly ResponsibilityRow[]; readonly gaps: { /** Rows with no A. */ readonly noAccountable: readonly string[]; /** Rows with no R. A derived C never fills either. */ readonly noResponsible: readonly string[]; }; /** People with no letter on any row of this matrix. */ readonly idle: readonly ResponsibilityPerson[]; } export interface ResponsibilityOptions { /** * The subjects that get a row, in any order; absent, every concept that is * not a person. A projection's subjects are the usual source. */ readonly rows?: readonly string[]; readonly projection?: string; } export declare function buildResponsibilityMatrix(workspace: string, graph: SemanticGraph, profileContext: ResolvedProfileContext, options?: ResponsibilityOptions): ResponsibilityMatrix; /** * The matrix as one markdown table a person reads, with the gaps and the * idle people under it. A C that comes only from attestations wears an * asterisk, so a standing role and a recorded judgement read differently. */ export declare function renderResponsibilityMarkdown(matrix: ResponsibilityMatrix): string;