Publish DevRunbook source
Managed validation / full (push) Successful in 3m18s

This commit is contained in:
DevRunbook release export
2026-09-03 04:09:17 +02:00
commit cfd2804e27
928 changed files with 161642 additions and 0 deletions
@@ -0,0 +1,236 @@
import { createHash } from 'node:crypto'
import { DomainError } from '@devrunbook/domain'
import {
authorizeWorkspaceAction,
type AuthenticatedActor,
type WorkspaceAuthorizationLookup,
} from '../auth/workspace-authorization'
import { lintPlaybookPackage } from '../quality/playbook-package-linter'
import {
evaluateStaticCase,
type QualityMatrix,
type StaticEvaluationCase,
type StaticEvaluationObservation,
type StaticEvaluationResult,
} from '../quality/static-quality-evaluation'
import {
parsePrivatePlaybookDraftEtag,
type PrivatePlaybookDraftStore,
} from './private-playbook-drafts'
export interface PrivatePlaybookQualityStore {
attestReview(attestation: {
readonly workspaceId: string
readonly versionId: string
readonly reviewedBy: string
readonly attestedDigest: string
readonly schemaAndSemanticValidationPassed: boolean
readonly blockingLintFindingCount: number
readonly limitationsDocumented: boolean
readonly unresolvedSafetyRegression: boolean
readonly review: Readonly<Record<string, unknown>>
readonly reviewedAt: Date
}): Promise<boolean>
upsertStaticCase(request: {
readonly workspaceId: string
readonly versionId: string
readonly evaluationCase: StaticEvaluationCase
readonly caseDigest: string
readonly now: Date
}): Promise<string | null>
appendStaticResult(request: {
readonly workspaceId: string
readonly versionId: string
readonly logicalCaseId: string
readonly fixtureVersion: string
readonly result: StaticEvaluationResult
readonly environment: Readonly<Record<string, unknown>>
readonly executedBy: string
readonly now: Date
}): Promise<string | null>
}
export interface PrivatePlaybookQualityDependencies {
readonly authorization: WorkspaceAuthorizationLookup
readonly drafts: PrivatePlaybookDraftStore
readonly quality: PrivatePlaybookQualityStore
readonly now: () => Date
}
interface QualityActorRequest {
readonly actor: AuthenticatedActor | null
readonly workspaceId: string
readonly versionId: string
readonly expectedEtag: string
}
async function authorizeEditor(
dependencies: PrivatePlaybookQualityDependencies,
request: QualityActorRequest,
): Promise<string> {
const context = await authorizeWorkspaceAction(dependencies.authorization, {
actor: request.actor,
workspaceId: request.workspaceId,
action: 'write',
})
return context.userId
}
async function currentDraft(
dependencies: PrivatePlaybookQualityDependencies,
request: QualityActorRequest,
) {
const draft = await dependencies.drafts.findVersionForWorkspace(
request.workspaceId,
request.versionId,
)
if (!draft)
throw new DomainError(
'private_playbook_not_found',
'Private playbook not found',
)
const expected = parsePrivatePlaybookDraftEtag(request.expectedEtag)
if (
expected.revision !== draft.draftRevision ||
expected.digest !== draft.draftDigest
) {
throw new DomainError(
'private_playbook_quality_conflict',
'The private playbook changed before evidence was recorded',
)
}
if (draft.publishedAt !== null) {
throw new DomainError(
'private_playbook_published_immutable',
'Published playbook versions cannot receive mutable draft evidence',
)
}
return draft
}
function canonical(value: unknown): unknown {
if (Array.isArray(value)) return value.map(canonical)
if (value !== null && typeof value === 'object') {
return Object.fromEntries(
Object.entries(value as Record<string, unknown>)
.sort(([left], [right]) => left.localeCompare(right, 'en'))
.map(([key, child]) => [key, canonical(child)]),
)
}
return value
}
function digest(value: unknown): string {
return createHash('sha256')
.update(JSON.stringify(canonical(value)), 'utf8')
.digest('hex')
}
function reviewNote(value: string): string {
const note = value.trim()
if (note.length < 1 || note.length > 4000) {
throw new DomainError(
'private_playbook_review_invalid',
'Review note must contain between 1 and 4000 characters',
)
}
return note
}
export async function reviewPrivatePlaybookDraft(
dependencies: PrivatePlaybookQualityDependencies,
request: QualityActorRequest & {
readonly limitationsDocumented: boolean
readonly unresolvedSafetyRegression: boolean
readonly note: string
},
) {
const reviewedBy = await authorizeEditor(dependencies, request)
const draft = await currentDraft(dependencies, request)
const lint = lintPlaybookPackage({
packageJson: draft.packageJson,
packageDigest: draft.draftDigest,
template: { path: 'template', content: draft.templateText },
published: false,
})
const blockingLintFindingCount = lint.findings.filter(
(finding) => finding.severity === 'error',
).length
const recorded = await dependencies.quality.attestReview({
workspaceId: request.workspaceId,
versionId: request.versionId,
reviewedBy,
attestedDigest: draft.draftDigest,
schemaAndSemanticValidationPassed: true,
blockingLintFindingCount,
limitationsDocumented: request.limitationsDocumented,
unresolvedSafetyRegression: request.unresolvedSafetyRegression,
review: { note: reviewNote(request.note), lint },
reviewedAt: dependencies.now(),
})
if (!recorded)
throw new DomainError(
'private_playbook_quality_conflict',
'The private playbook changed before review evidence was recorded',
)
return { digest: draft.draftDigest, lint, recorded: true as const }
}
export async function evaluatePrivatePlaybookStaticCase(
dependencies: PrivatePlaybookQualityDependencies,
request: QualityActorRequest & {
readonly evaluationCase: StaticEvaluationCase
readonly observation: StaticEvaluationObservation
readonly dimensions: QualityMatrix
readonly environment: Readonly<Record<string, unknown>>
},
) {
const executedBy = await authorizeEditor(dependencies, request)
const draft = await currentDraft(dependencies, request)
const target = request.evaluationCase.target
if (
target.id !== draft.logicalId ||
target.version !== draft.semanticVersion ||
target.digest !== draft.draftDigest
) {
throw new DomainError(
'private_playbook_evaluation_stale',
'Evaluation case target does not match the current draft',
)
}
const caseId = await dependencies.quality.upsertStaticCase({
workspaceId: request.workspaceId,
versionId: request.versionId,
evaluationCase: request.evaluationCase,
caseDigest: digest(request.evaluationCase),
now: dependencies.now(),
})
if (!caseId)
throw new DomainError(
'private_playbook_evaluation_conflict',
'The private playbook changed before the evaluation case was stored',
)
const result = evaluateStaticCase(
request.evaluationCase,
request.observation,
request.dimensions,
)
const resultId = await dependencies.quality.appendStaticResult({
workspaceId: request.workspaceId,
versionId: request.versionId,
logicalCaseId: request.evaluationCase.id,
fixtureVersion: request.evaluationCase.fixture.version,
result,
environment: request.environment,
executedBy,
now: dependencies.now(),
})
if (!resultId)
throw new DomainError(
'private_playbook_evaluation_conflict',
'The private playbook changed before the result was stored',
)
return { caseId, resultId, result }
}