Skip to content

Write NDJSON workflow run logs #413

Description

@NTCoding

Milestone: Delivery Plan: Riviere Extraction Workflows V1 — M4 (D4.2)
PRD: docs/project/PRD/riviere-extraction-workflows-v1/PRD.md §§1, 2, 3, 4, 5, 6
Architecture: docs/project/PRD/riviere-extraction-workflows-v1/ARCH.md §§3, 4, 6
Delivery plan: docs/project/PRD/riviere-extraction-workflows-v1/delivery.md §2, D4.2

Problem

The current Rivière graph-building process is made up of several manual steps that must be performed in order. This works for first-time learning and exploration, but once a user has created their first graph and wants to rebuild it inside a codebase, they must remember the steps or create their own custom scripts. That friction makes the process easy to forget, harder to repeat, and difficult to rely on in automated flows such as CI. At the project level, it risks Rivière feeling “like a toy” rather than a tool that can be set up in a project and “just works reliably”.

This ticket covers run-log visibility. The PRD requires clear stage progress and newline-delimited structured JSON run logs so users can understand what happened, inspect failures, fix the root cause, and re-run the workflow.

This slice matters because fail-fast workflows are only reliable when the user can see which stage failed and why.

Solution

Write one NDJSON run log for each workflow run and failure path. Logs must use searchable event types and include the approved lifecycle, stage, graph-write, completion, and failure events.

Agreed target architecture and design

Full architecture context

Read docs/project/PRD/riviere-extraction-workflows-v1/ARCH.md for the full approved architecture context and scope. This ticket is not a replacement for ARCH.md.

Target components, boundaries, and responsibilities

  • runId is generated once at command start as a sortable UTC timestamp plus random suffix, for example 20260505T182233Z-a1b2c3d4.
  • The run log destination is {runLog.directory}/{workflowName}/{runId}.ndjson, resolved under projectRoot.
  • The CLI boundary writes run logs for successful runs, workflow validation failures, referenced config failures, extraction failures, validation failures, graph write failures, and failed runs.
  • Run logs are written even when graph output is not written.
  • A failed run never updates graph.outputPath.
  • Each NDJSON line is one JSON object with at least { "type", "timestamp", "runId", "workflowName", "level" }.
  • Required event types are WorkflowStarted, WorkflowValidationFailed, StageStarted, StageCompleted, StageFailed, GraphWriteStarted, GraphWriteCompleted, WorkflowCompleted, and WorkflowFailed.
  • Stage events include stageName, stageType, and stageIndex.
  • Failure events include reason, errorCode, and any relevant configPath or outputPath.
  • If the log cannot be created before stages run, the command fails before extraction and leaves the graph unchanged.

Code/config/flow from ARCH.md

createWorkflowRunCommand
  ├─ createRunWorkflowInput(options)
  ├─ RunWorkflow.execute(input)
  │  ├─ RiviereProjectRepository.load({ projectRoot: input.projectRoot, workflowName: input.workflowName })
  │  │  ├─ WorkflowDefinitionFile.read(projectRoot, workflowName)
  │  │  ├─ GraphOptions.fromWorkflowDefinition(definition.graph)
  │  │  ├─ load extraction config/source state for each extract stage
  │  │  ├─ new ExtractionStage(stageName, resolvedConfig, moduleContexts, repositoryName)
  │  │  └─ RiviereProject.create(projectRoot, workflowName, graphOptions, stagePlan, extractionStages)
  │  └─ RiviereProject.rebuildGraph()
  │     ├─ RiviereBuilder.new(graphOptions)
  │     ├─ ExtractComponentsForGraph.execute(extractionStage, { allowIncomplete: false })
  │     ├─ ApplyExtractionToGraph.applyComponents(builder, stageName, repository, components)
  │     ├─ DetectExtractionConnections.execute(extractionStage, allComponents, { allowIncomplete: false })
  │     ├─ ApplyExtractionToGraph.applyLinks(builder, stageName, links, externalLinks)
  │     ├─ RiviereBuilder.validate()
  │     └─ RiviereBuilder.build()
  └─ presentWorkflowRunResult(result)
packages/riviere-cli/src/features/workflow/entrypoint/run-workflow.ts
packages/riviere-cli/src/features/workflow/entrypoint/run-workflow/present-workflow-run-result.ts

Role and location decisions

Proposed Element Kind Role Sublocation Confidence Notes
presentWorkflowRunResult function cli-output-formatter / entrypoint-local output writer role from approved architecture packages/riviere-cli/src/features/workflow/entrypoint/run-workflow High CLI boundary output handler that writes NDJSON run logs.
Run log event model type/interface command-use-case-result-value or approved existing result-value role packages/riviere-cli/src/features/workflow/commands or approved result boundary Medium Carries events from the run result without moving CLI file writing into domain code.
RunWorkflowResult type/interface command-use-case-result packages/riviere-cli/src/features/workflow/commands High Carries graph build success/failure, run events, run log path, and failure detail.

If implementation requires a role or location not approved by .riviere or ARCH.md, stop and ask for approval before adding it.

Structural concerns and forbidden alternatives

  • Do not write run logs from RiviereProject.
  • Do not write run logs from RunWorkflow.
  • Do not add workflow presentation files under the older infra/cli/output pattern.
  • Do not add CI-specific observability, annotations, job summaries, or reporting.
  • Do not omit failure logs when graph output is not written.
  • Do not hide missing log fields behind fallback values.

Design challenge instruction

If implementation reveals the agreed design is impractical, incomplete, or sub-optimal, stop and push back. Do not silently implement a different design.

What "done" looks like

Product

  • Each workflow run creates one NDJSON run log.
  • Each log line is one JSON object.
  • Each event includes at least type, timestamp, runId, workflowName, and level.
  • Required event types are emitted: WorkflowStarted, WorkflowValidationFailed, StageStarted, StageCompleted, StageFailed, GraphWriteStarted, GraphWriteCompleted, WorkflowCompleted, and WorkflowFailed.
  • Stage events include stageName, stageType, and stageIndex.
  • Failure events include reason, errorCode, and relevant configPath or outputPath.
  • Logs are written for successful runs, validation failures, referenced config failures, extraction failures, stage failures, graph write failures, and completed failures.
  • If the log cannot be created before stages run, the command fails before extraction.

Design

  • Run-log writing happens at the CLI boundary through the approved entrypoint-local workflow presentation/output handling.
  • RiviereProject returns events and failure details but does not write log files.
  • RunWorkflow returns results but does not write log files.
  • Run logs are written even when graph output is not written.
  • Failed runs never update graph.outputPath.

Quality

  • Tests inspect NDJSON output for required event fields.
  • Tests inspect NDJSON output for required event types.
  • Tests inspect success logs and failure logs.
  • Tests prove log creation failure stops before extraction.
  • Tests assert exact JSON event values where inputs are deterministic.
  • No ticket-specific performance, accessibility, security, privacy, or compatibility criteria were identified beyond repository standards.

Implementation guidelines

Change areas

  • packages/riviere-cli/src/features/workflow/entrypoint/run-workflow.ts
  • packages/riviere-cli/src/features/workflow/entrypoint/run-workflow/present-workflow-run-result.ts
  • packages/riviere-cli/src/features/workflow/commands/run-workflow-result.ts
  • Tests for NDJSON run logs and log failure paths.
  • Avoid RiviereProject file writing.
  • Avoid RunWorkflow file writing.

Relevant repository rules

  • docs/conventions/software-design.md — SD-001 Fail-fast over silent fallbacks.
  • docs/conventions/software-design.md — SD-002 No any or unsafe type assertions.
  • docs/conventions/software-design.md — SD-003 Make illegal states unrepresentable.
  • docs/conventions/software-design.md — SD-005 Intention-revealing names only.
  • docs/conventions/software-design.md — SD-007 Use Zod for runtime validation at boundaries.
  • docs/conventions/software-design.md — SD-020 Prefer immutability.
  • docs/conventions/testing.md — TS-001 Test names describe outcomes.
  • docs/conventions/testing.md — TS-002 Assertions must match test titles.
  • docs/conventions/testing.md — TS-003 Assert specific values.
  • docs/conventions/testing.md — TS-004 One concept per test.
  • docs/conventions/testing.md — TS-005 Bugs cluster together.

Relevant architecture memories

  • project-memory/architecture/memories/ddd-modelling-trade-offs-from-riviere-workflows.md — CLI output policy belongs at the CLI boundary.
  • project-memory/architecture/memories/rejected-workflow-use-case-dumping-case-study.md — domain results must not expose command/use-case conversion, and use cases must not take over output writing.

Lint, role-check, and test expectations

  • This ticket touches role-enforced TypeScript. Expect lint and role-check feedback and use it to improve the design rather than working around it.
  • Exact package-level lint, role-check, and test commands were not named in the approved PRD, architecture, delivery plan, .riviere role configuration, or convention files used for task creation.
  • Tests must parse NDJSON and assert specific event objects, not only assert file existence.

Dependencies

How to verify

  • Test review confirms NDJSON output contains required event fields.
  • Test review confirms NDJSON output contains all required event types.
  • Test review confirms success logs and failure logs are covered.
  • Test review confirms log creation failure stops before extraction.
  • Reviewer inspection confirms log writing is not inside RiviereProject or RunWorkflow.
  • Reviewer inspection confirms workflow presentation/output is not added under the older infra/cli/output pattern.
  • Reviewer inspection confirms no CI-specific observability, annotations, job summaries, or reporting was added.

Things this ticket must not do

  • Do not add CI-specific observability, annotations, job summaries, or reporting.
  • Do not write run logs from RiviereProject.
  • Do not write run logs from RunWorkflow.
  • Do not add presentation/output files under the older infra/cli/output pattern.
  • Do not add plan-first/preview mode.
  • Do not add arbitrary shell-command stages or generic task-runner behaviour.

Glossary

Source glossary: docs/architecture/domain-terminology/contextive/definitions.glossary.yml.

  • Component: A discrete unit of software functionality in a Riviere graph. Has a type, belongs to a domain, and connects to other components via links.
  • Link: A directed connection between two components, representing a call, dependency, or event flow. Has a source and target component ID, and optionally a type (sync/async).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions