Payload/scripts/kaden/harness/harness-journal.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Journal CLI for the harness event ledger (start / stop / instant / adjust). .DESCRIPTION Appends accounting-style events to docs/harness/features/<slug>/journal/events.jsonl (schema harness.journal.event/v1). This is the source of truth for *what happened*. Fits the big picture (docs/kaden/harness-journal.md): - Journal = ledger (append-only; correcting entries via -Action adjust). - .review-loop.json = gate view (schema 1.2 projection). Pass -RebuildProjection to rebuild that view from the journal after a write. - Gate decisions still come from validate-review-loop against projection + artifacts - never from journal narrative alone. Prefer calling this (or emitters on harness-record-phase / harness-sensor) instead of hand-editing JSONL. See docs/kaden/harness-journal-blueprint.md. .PARAMETER Summary Human-readable activity summary. Alias: -Note (agents often guess -Note; both are accepted). .EXAMPLE .\scripts\kaden\harness-journal.ps1 -Feature harness-event-journal -Slice journal-gate-skeleton -Action start -ActivityType slice.phase -ActivityName RED -ActivityId act_demo -Summary 'RED start' .EXAMPLE .\scripts\kaden\harness-journal.ps1 -Feature harness-event-journal -Slice journal-gate-skeleton -Action adjust -ActivityType blocker -ActivityName review-ready-blocked-evidence -AmendsEventId <event_id> -Summary 'Adjustment: attach original sensor paths' .EXAMPLE .\scripts\kaden\harness-journal.ps1 -Feature harness-event-journal -Slice journal-gate-skeleton -Action stop -ActivityType slice.phase -ActivityName RED -ActivityId act_demo -Outcome PASS -RebuildProjection #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Feature, [string]$Slice = '', [Parameter(Mandatory = $true)] [ValidateSet('start', 'stop', 'instant', 'adjust')] [string]$Action, [ValidateSet('pipeline.phase', 'slice.phase', 'review.cycle', 'sensor', 'validation', 'handoff', 'blocker', 'turn', 'artifact', 'other')] [string]$ActivityType = 'other', [string]$ActivityName = '', [string]$ActivityId = '', [ValidateSet('PASS', 'FAIL', 'BLOCKED', 'SKIPPED', 'PASS_WITH_FINDINGS')] [string]$Outcome = 'PASS', [ValidateSet( 'ActivityStarted', 'ActivityStopped', 'ActivityAdjusted', 'PhaseStatusChanged', 'SensorRunRecorded', 'GateCheckRun', 'GateRelevantValidationRun', 'GateValidationPassed', 'ReviewerCycleRecorded', 'HandoffRecorded', 'HumanGateDecided', 'OwnershipChanged', 'BlockerDeclared', 'EmissionGapMarked', 'TaskStarted', 'TaskHeartbeat', 'TaskTimedOut', 'TaskRecovered', 'TaskAbandoned', 'ArtifactRegistered' )] [string]$Kind = 'ActivityStarted', [Alias('Note')] [string]$Summary = '', [string]$AmendsEventId = '', [string]$OccurredAt = '', [string]$FeatureRoot = '', [string]$RepoRoot = '', [ValidateSet('cursor', 'copilot', 'other')] [string]$ModelProvider = 'other', [string]$ModelSlug = 'unknown', [ValidateSet('primary', 'subagent')] [string]$ModelRole = 'primary', [string]$Agent = 'atdd-developer', [string]$ParentAgent = '', [string]$Tool = 'harness-script', [switch]$RebuildProjection, [switch]$AllowArbitraryFeatureRoot, [string]$SkipReasonCode = '' ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $contractPath = Join-Path $PSScriptRoot 'lib\HarnessContract.psm1' $journalPath = Join-Path $PSScriptRoot 'lib\HarnessJournal.psm1' $projectionPath = Join-Path $PSScriptRoot 'lib\HarnessGateProjection.psm1' Import-Module $contractPath -Force Import-Module $journalPath -Force Import-Module $projectionPath -Force Test-HarnessContractModuleReady if ([string]::IsNullOrWhiteSpace($RepoRoot)) { $RepoRoot = Get-HarnessRepoRoot -StartPath $PSScriptRoot } $featureRootPath = Get-HarnessFeatureRoot -RepoRoot $RepoRoot -Feature $Feature -FeatureRootOverride $FeatureRoot -AllowArbitraryFeatureRoot:$AllowArbitraryFeatureRoot if ([string]::IsNullOrWhiteSpace($ActivityId)) { $ActivityId = New-HarnessJournalActivityId } if ([string]::IsNullOrWhiteSpace($ActivityName)) { $ActivityName = $Action } $actor = New-HarnessJournalActor -Agent $Agent -ParentAgent $(if ($ParentAgent) { $ParentAgent } else { $null }) ` -Tool $Tool -Provider $ModelProvider -Slug $ModelSlug -Role $ModelRole $sliceArg = if ([string]::IsNullOrWhiteSpace($Slice)) { $null } else { $Slice } $evt = $null switch ($Action) { 'start' { $evt = Start-HarnessJournalActivity -FeatureRoot $featureRootPath -Feature $Feature -Slice $sliceArg ` -ActivityId $ActivityId -ActivityType $ActivityType -ActivityName $ActivityName ` -Actor $actor -Summary $Summary -OccurredAt $OccurredAt } 'stop' { $stopPayload = $null if (-not [string]::IsNullOrWhiteSpace($SkipReasonCode)) { $stopPayload = [pscustomobject]@{ skip_reason_code = $SkipReasonCode } } $evt = Stop-HarnessJournalActivity -FeatureRoot $featureRootPath -Feature $Feature -Slice $sliceArg ` -ActivityId $ActivityId -ActivityType $ActivityType -ActivityName $ActivityName ` -Outcome $Outcome -Actor $actor -Summary $Summary -Payload $stopPayload -OccurredAt $OccurredAt } 'instant' { $activity = New-HarnessJournalActivity -Id $ActivityId -Type $ActivityType -Name $ActivityName -Role 'instant' if ([string]::IsNullOrWhiteSpace($Summary)) { $Summary = "$ActivityName ($Kind)" } $evt = Add-HarnessJournalEvent -FeatureRoot $featureRootPath -Feature $Feature -Slice $sliceArg ` -Kind $Kind -Activity $activity -Actor $actor -Outcome $(if ($Kind -eq 'ActivityStarted') { $null } else { $Outcome }) ` -Summary $Summary -OccurredAt $OccurredAt } 'adjust' { if ([string]::IsNullOrWhiteSpace($AmendsEventId)) { throw '-AmendsEventId is required for -Action adjust' } if ([string]::IsNullOrWhiteSpace($Summary)) { $Summary = "adjusting entry for $AmendsEventId" } $activity = New-HarnessJournalActivity -Id $ActivityId -Type $ActivityType -Name $ActivityName -Role 'adjust' $evt = Add-HarnessJournalAdjustingEntry -FeatureRoot $featureRootPath -Feature $Feature -Slice $sliceArg ` -AmendsEventId $AmendsEventId -Summary $Summary -Activity $activity -Actor $actor -OccurredAt $OccurredAt } } if ($RebuildProjection) { Update-HarnessGateProjectionFromJournal -FeatureRoot $featureRootPath -Feature $Feature -RepoRoot $RepoRoot -Write | Out-Null } $evt | ConvertTo-Json -Depth 10 -Compress |