From bfee763ab27ee3393dfaa9fdb24d9b57dd909e2e Mon Sep 17 00:00:00 2001 From: MerlinH Date: Sun, 26 Jul 2026 05:43:06 +0000 Subject: [PATCH] feat: compact workflow status context --- .truthmark/config.yml | 2 -- ...07-10-harden-init-routing-and-lifecycle.md | 1 + .../config-route-and-check-contracts.md | 10 ++++-- .../repository/repository-intelligence.md | 6 +++- docs/truthmark/routes/areas.md | 3 +- .../routes/areas/installed-workflows.md | 3 +- src/cli/handlers.ts | 32 ++++++++++++++++++- src/workflow-state/build.ts | 15 ++++++--- tests/cli/index-impact-context.test.ts | 16 ++++++++++ tests/workflow-state/build.test.ts | 20 ++++++++++++ 10 files changed, 95 insertions(+), 13 deletions(-) diff --git a/.truthmark/config.yml b/.truthmark/config.yml index bb67e73..399a61a 100644 --- a/.truthmark/config.yml +++ b/.truthmark/config.yml @@ -11,8 +11,6 @@ truthmark: generated: portal: enabled: false -instruction_targets: - - AGENTS.md frontmatter: required: [] recommended: diff --git a/changes/2026-07-10-harden-init-routing-and-lifecycle.md b/changes/2026-07-10-harden-init-routing-and-lifecycle.md index 520038b..beb748c 100644 --- a/changes/2026-07-10-harden-init-routing-and-lifecycle.md +++ b/changes/2026-07-10-harden-init-routing-and-lifecycle.md @@ -10,3 +10,4 @@ SemVer rationale: This is a backward-compatible release that adds platform-deriv - Check and RepoIndex share Git-visible, NUL-safe repository discovery, including functional code under arbitrary roots. - Init reconciles exact safely recognized inactive generated surfaces while preserving diverged, Gemini, and unrelated files. - `truthmark uninstall --dry-run|--apply [--json]` provides a deterministic removal plan and preserves authored truth, configuration, templates, Portal output, and global package installation. +- Human-readable `truthmark workflow status` output now presents bounded applicability and advisory context while JSON retains the full schema-versioned contract; duplicate diagnostics are collapsed at WorkflowState composition. diff --git a/docs/truthmark/engineering/contracts/config-route-and-check-contracts.md b/docs/truthmark/engineering/contracts/config-route-and-check-contracts.md index 14a5746..63d2850 100644 --- a/docs/truthmark/engineering/contracts/config-route-and-check-contracts.md +++ b/docs/truthmark/engineering/contracts/config-route-and-check-contracts.md @@ -1,7 +1,7 @@ --- status: active truth_kind: engineering-contract -last_reviewed: 2026-06-20 +last_reviewed: 2026-07-26 --- # Config, Route, And Check Contracts @@ -47,7 +47,7 @@ Conflicting duplicate kinds or lanes are reported as area-index errors. The public ContextPack command surface is retired. -Agents use `truthmark workflow status --workflow [--base ] --json` for: +Agents use `truthmark workflow status --workflow [--base ]` for a bounded human-readable advisory card and add `--json` when they need the schema-versioned contract for: - an advisory workflow card - write-boundary suggestions @@ -61,6 +61,10 @@ Agents use `truthmark workflow status --workflow [--base ] --jso - next steps - compact affected-test guidance +The human-readable card reports applicability and non-empty affected files, likely route owners, suggested truth docs, open questions, and next steps. Each list is capped at five entries with a remaining-count summary. + +WorkflowState composes diagnostics from config, RepoIndex, ImpactSet, and Check by exact-value deduplication so the same review or error signal appears once. + Agents use `truthmark impact --base --json` for branch-diff routing. These replacement JSON outputs emit paths, metadata, diagnostics, and command arrays only. @@ -121,6 +125,8 @@ The target model is lane-first and does not use `docs/truthmark/truth` as the ca - Decision (2026-06-15): Route relationships are route-local metadata; checks validate relationship targets for existence and lane compatibility without requiring a reciprocal global graph edge. - Decision (2026-06-15): ContextPack is folded into workflow status and impact; the standalone `truthmark context` command is hard-removed from the public CLI. - Decision (2026-06-18): Omitted `platforms` normalize to an empty platform list; all host-specific generated surfaces, including Codex, are explicit opt-in config. +- Decision (2026-07-26): Human workflow status reuses the existing advisory card with bounded lists, while JSON retains the full schema-versioned state. + - Exact duplicate diagnostics are collapsed at WorkflowState composition so optional helper output stays compact without hiding distinct signals. ## Rationale diff --git a/docs/truthmark/engineering/repository/repository-intelligence.md b/docs/truthmark/engineering/repository/repository-intelligence.md index 3a9278f..ae974bd 100644 --- a/docs/truthmark/engineering/repository/repository-intelligence.md +++ b/docs/truthmark/engineering/repository/repository-intelligence.md @@ -1,7 +1,7 @@ --- status: active truth_kind: engineering-behavior -last_reviewed: 2026-06-26 +last_reviewed: 2026-07-26 --- # Repository Intelligence @@ -42,6 +42,8 @@ It covers RepoIndex, RouteMap, ImpactSet, evidence validation, freshness, and Wo - next steps - report sections - The advisory card presents affected files, likely route owners, suggested truth docs, open questions, and skipped optional-helper status so helper output remains review material rather than repository authority. +- Human workflow status renders applicability plus non-empty advisory-card and next-step lists, capped at five entries per list; JSON retains the complete WorkflowState contract. +- WorkflowState collapses exact duplicate diagnostics collected from config, RepoIndex, ImpactSet, and Check while preserving distinct diagnostics. - Workflow applicability uses context-shaped states such as `ready`, `needs_manual_review`, and `needs_routing_review`. - Diagnostics or missing route ownership produce open questions and manual handoff guidance instead of making the CLI the arbiter. - `truthmark-sync` includes `Sync Intent` in its report sections as a transient pre-write checklist and keeps affected truth docs in `targetTruthDocs` for review focus. @@ -125,6 +127,8 @@ It covers RepoIndex, RouteMap, ImpactSet, evidence validation, freshness, and Wo - Decision (2026-06-21): Sync `candidateStaleTruthDocs` stays signal-based. - WorkflowState does not enumerate every indexed truth doc outside the impact set. - It returns an empty candidate list unless freshness, relationships, source references, changed route metadata, or changed linked docs indicate a possible stale-truth repair. +- Decision (2026-07-26): Human workflow status renders the existing advisory card as bounded context rather than requiring callers to load the full JSON contract. + - WorkflowState removes exact duplicate diagnostics at its composition boundary. ## Rationale diff --git a/docs/truthmark/routes/areas.md b/docs/truthmark/routes/areas.md index 840f3d8..3423bc4 100644 --- a/docs/truthmark/routes/areas.md +++ b/docs/truthmark/routes/areas.md @@ -1,7 +1,7 @@ --- status: active doc_type: routing -last_reviewed: 2026-05-16 +last_reviewed: 2026-07-26 --- # Truthmark Areas @@ -85,6 +85,7 @@ Code surface: - src/templates/workflow-surfaces.ts - src/templates/generated-surfaces.ts - src/checks/generated-surfaces.ts +- src/managed-block.ts - src/truth/\*\* - src/version.ts - workflow-eval-framwork/\*\* diff --git a/docs/truthmark/routes/areas/installed-workflows.md b/docs/truthmark/routes/areas/installed-workflows.md index 355981a..a3170c8 100644 --- a/docs/truthmark/routes/areas/installed-workflows.md +++ b/docs/truthmark/routes/areas/installed-workflows.md @@ -1,7 +1,7 @@ --- status: active doc_type: routing -last_reviewed: 2026-05-16 +last_reviewed: 2026-07-26 --- # Installed Workflows Areas @@ -40,6 +40,7 @@ Code surface: - src/templates/workflow-surfaces.ts - src/templates/generated-surfaces.ts - src/checks/generated-surfaces.ts +- src/managed-block.ts - src/truth/\*\* - src/version.ts - workflow-eval-framwork/\*\* diff --git a/src/cli/handlers.ts b/src/cli/handlers.ts index abada32..c226fb7 100644 --- a/src/cli/handlers.ts +++ b/src/cli/handlers.ts @@ -12,6 +12,7 @@ import { type TruthmarkWorkflowId, } from "../agents/workflow-manifest.js"; import { buildWorkflowState } from "../workflow-state/build.js"; +import type { WorkflowState } from "../workflow-state/types.js"; import fs from "node:fs/promises"; import { @@ -130,6 +131,35 @@ const invalidWorkflowResult = ( }, }); +const summarizeValues = (values: string[]): string => + values.length <= 5 + ? values.join(", ") + : `${values.slice(0, 5).join(", ")} (+${values.length - 5} more)`; + +const renderWorkflowStatusSummary = (state: WorkflowState): string => { + const card = state.workflowCard; + + return [ + `Truthmark workflow status completed for ${state.workflow}.`, + `Applicability: ${state.applicability.state}.`, + ...(card.affectedFiles.length > 0 + ? [`Affected files: ${summarizeValues(card.affectedFiles)}`] + : []), + ...(card.likelyRouteOwners.length > 0 + ? [`Likely route owners: ${summarizeValues(card.likelyRouteOwners)}`] + : []), + ...(card.suggestedTruthDocs.length > 0 + ? [`Suggested truth docs: ${summarizeValues(card.suggestedTruthDocs)}`] + : []), + ...(card.openQuestions.length > 0 + ? [`Open questions: ${summarizeValues(card.openQuestions)}`] + : []), + ...(state.nextSteps.length > 0 + ? [`Next steps: ${summarizeValues(state.nextSteps)}`] + : []), + ].join("\n"); +}; + const readHelperFile = async ( filePath: string, helper: string, @@ -193,7 +223,7 @@ export const runWorkflowStatus = async (options: { return { command: "workflow status", - summary: `Truthmark workflow status completed for ${options.workflow}.`, + summary: renderWorkflowStatusSummary(workflowState), diagnostics: workflowState.diagnostics, data: { request: { diff --git a/src/workflow-state/build.ts b/src/workflow-state/build.ts index c740654..1ef2589 100644 --- a/src/workflow-state/build.ts +++ b/src/workflow-state/build.ts @@ -153,7 +153,8 @@ const candidateStaleTruthDocsFor = ( doc.sourceOfTruth.some((reference) => [...changedPaths].some( (changedPath) => - reference === changedPath || micromatch.isMatch(changedPath, reference), + reference === changedPath || + micromatch.isMatch(changedPath, reference), ), ) ) { @@ -363,10 +364,14 @@ export const buildWorkflowState = async ( comparisonBase ? { base: comparisonBase } : {}, ); const diagnostics = [ - ...loadResult.diagnostics, - ...repoIndex.diagnostics, - ...(impactSet?.diagnostics ?? []), - ...checkResult.diagnostics, + ...new Map( + [ + ...loadResult.diagnostics, + ...repoIndex.diagnostics, + ...(impactSet?.diagnostics ?? []), + ...checkResult.diagnostics, + ].map((diagnostic) => [JSON.stringify(diagnostic), diagnostic] as const), + ).values(), ]; const applicability = applicabilityFor( options.workflow, diff --git a/tests/cli/index-impact-context.test.ts b/tests/cli/index-impact-context.test.ts index c265f6f..33dd1b8 100644 --- a/tests/cli/index-impact-context.test.ts +++ b/tests/cli/index-impact-context.test.ts @@ -192,6 +192,22 @@ describe("repository intelligence CLI commands", () => { expect(Array.isArray(state.nextSteps)).toBe(true); expect(Array.isArray(state.diagnostics)).toBe(true); expect(compactTestGuidance.join("\n")).toContain("tests/math.test.ts"); + + const humanResult = await runCli( + [ + "workflow", + "status", + "--workflow", + "truthmark-sync", + "--base", + "main", + ], + { cwd: repo.rootDir }, + ); + expect(humanResult.stdout).toContain("Applicability: ready."); + expect(humanResult.stdout).toContain("Affected files: src/math.ts"); + expect(humanResult.stdout).toContain("Likely route owners:"); + expect(humanResult.stdout).toContain("Suggested truth docs:"); } finally { await repo.cleanup(); } diff --git a/tests/workflow-state/build.test.ts b/tests/workflow-state/build.test.ts index e19bdfa..14d2753 100644 --- a/tests/workflow-state/build.test.ts +++ b/tests/workflow-state/build.test.ts @@ -323,6 +323,26 @@ describe("buildWorkflowState", () => { expect(JSON.stringify(state)).not.toContain('"content":'); }); + it("deduplicates diagnostics composed from repository helpers", async () => { + const repo = await setupConfiguredRepo(); + repos.push(repo); + await repo.writeFile( + ".truthmark/config.yml", + `${await repo.readFile(".truthmark/config.yml")}instruction_targets:\n - AGENTS.md\n`, + ); + + const state = await buildWorkflowState(repo.rootDir, { + workflow: "truthmark-sync", + base: "main", + }); + + expect( + state.diagnostics.filter((diagnostic) => + diagnostic.message.includes("instruction_targets"), + ), + ).toHaveLength(1); + }); + it("authorizes sync to correct signal-linked truth docs and routing files", async () => { const repo = await setupConfiguredRepo({ includeUnrelatedRoute: true }); repos.push(repo);