← back to Cli Printing Press
fix(cli): sync root highlights from verified features (#549)
8b099ba060cdae07197d40c3b709eef17e04391b · 2026-05-03 18:18:49 -0700 · Trevin Chow
Sync dogfood-derived novel feature artifacts loudly, including root help Highlights.
Files touched
M internal/pipeline/climanifest.goM internal/pipeline/docsync.goM internal/pipeline/dogfood.goM internal/pipeline/dogfood_test.goM skills/printing-press/SKILL.mdM testdata/golden/expected/dogfood-novel-doc-sync/stderr.txt
Diff
commit 8b099ba060cdae07197d40c3b709eef17e04391b
Author: Trevin Chow <trevin@trevinchow.com>
Date: Sun May 3 18:18:49 2026 -0700
fix(cli): sync root highlights from verified features (#549)
Sync dogfood-derived novel feature artifacts loudly, including root help Highlights.
---
internal/pipeline/climanifest.go | 19 +-
internal/pipeline/docsync.go | 196 +++++++++++++++++++--
internal/pipeline/dogfood.go | 15 +-
internal/pipeline/dogfood_test.go | 78 +++++++-
skills/printing-press/SKILL.md | 6 +-
.../expected/dogfood-novel-doc-sync/stderr.txt | 3 +
6 files changed, 293 insertions(+), 24 deletions(-)
diff --git a/internal/pipeline/climanifest.go b/internal/pipeline/climanifest.go
index 9036330c..19e2b0b8 100644
--- a/internal/pipeline/climanifest.go
+++ b/internal/pipeline/climanifest.go
@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "reflect"
"strings"
"time"
@@ -164,27 +165,31 @@ func novelFeaturesToManifest(features []NovelFeature) []NovelFeatureManifest {
// SyncCLIManifestNovelFeatures records dogfood-verified novel features in the
// generated CLI manifest. Empty verified sets intentionally leave the manifest
// untouched so a failed or incomplete dogfood pass cannot erase prior metadata.
-func SyncCLIManifestNovelFeatures(dir string, features []NovelFeature) error {
+func SyncCLIManifestNovelFeatures(dir string, features []NovelFeature) (bool, error) {
if len(features) == 0 {
- return nil
+ return false, nil
}
manifestPath := filepath.Join(dir, CLIManifestFilename)
data, err := os.ReadFile(manifestPath)
if err != nil {
if os.IsNotExist(err) {
- return nil
+ return false, nil
}
- return fmt.Errorf("reading CLI manifest: %w", err)
+ return false, fmt.Errorf("reading CLI manifest: %w", err)
}
var m CLIManifest
if err := json.Unmarshal(data, &m); err != nil {
- return fmt.Errorf("parsing CLI manifest: %w", err)
+ return false, fmt.Errorf("parsing CLI manifest: %w", err)
}
- m.NovelFeatures = novelFeaturesToManifest(features)
+ updated := novelFeaturesToManifest(features)
+ if reflect.DeepEqual(m.NovelFeatures, updated) {
+ return false, nil
+ }
+ m.NovelFeatures = updated
- return WriteCLIManifest(dir, m)
+ return true, WriteCLIManifest(dir, m)
}
// findArchivedSpec looks for a spec file archived alongside a generated CLI.
diff --git a/internal/pipeline/docsync.go b/internal/pipeline/docsync.go
index bc016b26..deff61ac 100644
--- a/internal/pipeline/docsync.go
+++ b/internal/pipeline/docsync.go
@@ -12,43 +12,82 @@ type novelFeatureDocGroup struct {
Features []NovelFeature
}
+type syncedArtifact struct {
+ Path string
+ Detail string
+}
+
// SyncCLITranscendenceDocs rewrites generated README/SKILL transcendence
// blocks from dogfood-verified features. Empty verified sets remove the blocks.
-func SyncCLITranscendenceDocs(dir string, features []NovelFeature) error {
- if err := syncMarkdownFeatureSection(
+func SyncCLITranscendenceDocs(dir string, features []NovelFeature) ([]syncedArtifact, error) {
+ var synced []syncedArtifact
+ changed, err := syncMarkdownFeatureSection(
filepath.Join(dir, "README.md"),
"## Unique Features",
renderNovelFeatureDocSection("## Unique Features", features),
[]string{"## Usage"},
- ); err != nil {
- return err
+ )
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ synced = append(synced, syncedArtifact{Path: "README.md", Detail: "Unique Features"})
}
- return syncMarkdownFeatureSection(
+ changed, err = syncMarkdownFeatureSection(
filepath.Join(dir, "SKILL.md"),
"## Unique Capabilities",
renderNovelFeatureDocSection("## Unique Capabilities", features),
[]string{"## HTTP Transport", "## Discovery Signals", "## Command Reference", "## Auth Setup"},
)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ synced = append(synced, syncedArtifact{Path: "SKILL.md", Detail: "Unique Capabilities"})
+ }
+ return synced, nil
+}
+
+// SyncCLIRootHighlights rewrites root --help Highlights from dogfood-verified
+// features. It edits only the generated Long-string section so hand-authored
+// command registration changes in root.go are left intact.
+func SyncCLIRootHighlights(dir string, features []NovelFeature) (bool, error) {
+ path := filepath.Join(dir, "internal", "cli", "root.go")
+ data, err := os.ReadFile(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return false, nil
+ }
+ return false, fmt.Errorf("reading %s: %w", path, err)
+ }
+ updated := replaceRootLongHighlights(string(data), features)
+ if updated == string(data) {
+ return false, nil
+ }
+ if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
+ return false, fmt.Errorf("writing %s: %w", path, err)
+ }
+ return true, nil
}
-func syncMarkdownFeatureSection(path, heading, replacement string, insertBefore []string) error {
+func syncMarkdownFeatureSection(path, heading, replacement string, insertBefore []string) (bool, error) {
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
- return nil
+ return false, nil
}
- return fmt.Errorf("reading %s: %w", path, err)
+ return false, fmt.Errorf("reading %s: %w", path, err)
}
updated := replaceMarkdownSection(string(data), heading, replacement, insertBefore)
if updated == string(data) {
- return nil
+ return false, nil
}
if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
- return fmt.Errorf("writing %s: %w", path, err)
+ return false, fmt.Errorf("writing %s: %w", path, err)
}
- return nil
+ return true, nil
}
func renderNovelFeatureDocSection(heading string, features []NovelFeature) string {
@@ -214,3 +253,138 @@ func findNextLevelTwoHeading(content string, after int) int {
}
return len(content)
}
+
+const rootHighlightsHeading = "Highlights (not in the official API docs):"
+
+func replaceRootLongHighlights(content string, features []NovelFeature) string {
+ longIdx := strings.Index(content, "Long:")
+ if longIdx < 0 {
+ return content
+ }
+ openRel := strings.Index(content[longIdx:], "`")
+ if openRel < 0 {
+ return content
+ }
+ bodyStart := longIdx + openRel + 1
+ closeRel := strings.Index(content[bodyStart:], "`")
+ if closeRel < 0 {
+ return content
+ }
+ bodyEnd := bodyStart + closeRel
+
+ body := content[bodyStart:bodyEnd]
+ updatedBody := replaceRootLongHighlightsBody(body, renderRootHighlights(features))
+ if updatedBody == body {
+ return content
+ }
+ return content[:bodyStart] + updatedBody + content[bodyEnd:]
+}
+
+func replaceRootLongHighlightsBody(body, replacement string) string {
+ headingStart := strings.Index(body, rootHighlightsHeading)
+ if headingStart >= 0 {
+ sectionEnd := findRootLongFooter(body, headingStart+len(rootHighlightsHeading))
+ if sectionEnd < 0 {
+ sectionEnd = len(body)
+ }
+ return joinRootLongParts(body[:headingStart], replacement, body[sectionEnd:])
+ }
+ if strings.TrimSpace(replacement) == "" {
+ return body
+ }
+ footerStart := findRootLongFooter(body, 0)
+ if footerStart < 0 {
+ return joinRootLongParts(body, replacement, "")
+ }
+ return joinRootLongParts(body[:footerStart], replacement, body[footerStart:])
+}
+
+func findRootLongFooter(body string, after int) int {
+ if after < 0 {
+ after = 0
+ }
+ if after > len(body) {
+ return -1
+ }
+ for _, marker := range []string{"\n\nAgent mode:", "\n\nAdd --agent"} {
+ if idx := strings.Index(body[after:], marker); idx >= 0 {
+ return after + idx + 2
+ }
+ }
+ for _, marker := range []string{"Agent mode:", "Add --agent"} {
+ if idx := strings.Index(body[after:], marker); idx >= 0 {
+ return after + idx
+ }
+ }
+ return -1
+}
+
+func renderRootHighlights(features []NovelFeature) string {
+ if len(features) == 0 {
+ return ""
+ }
+ shown := features
+ overflow := 0
+ if len(shown) > 15 {
+ overflow = len(shown) - 15
+ shown = shown[:15]
+ }
+
+ var b strings.Builder
+ b.WriteString(rootHighlightsHeading)
+ b.WriteString("\n")
+ for _, feature := range shown {
+ b.WriteString(" • ")
+ b.WriteString(goRawSafe(feature.Command))
+ b.WriteString(" ")
+ b.WriteString(goRawSafe(truncateRunes(feature.Description, 200)))
+ b.WriteString("\n")
+ }
+ if overflow > 0 {
+ fmt.Fprintf(&b, " …and %d more — see README.md for the full list\n", overflow)
+ }
+ return strings.TrimRight(b.String(), "\n")
+}
+
+func joinRootLongParts(prefix, middle, suffix string) string {
+ prefix = strings.TrimRight(prefix, "\n")
+ middle = strings.Trim(middle, "\n")
+ suffix = strings.TrimLeft(suffix, "\n")
+
+ switch {
+ case middle == "":
+ if prefix == "" {
+ return suffix
+ }
+ if suffix == "" {
+ return prefix
+ }
+ return prefix + "\n\n" + suffix
+ case prefix == "" && suffix == "":
+ return middle
+ case prefix == "":
+ return middle + "\n\n" + suffix
+ case suffix == "":
+ return prefix + "\n\n" + middle
+ default:
+ return prefix + "\n\n" + middle + "\n\n" + suffix
+ }
+}
+
+func truncateRunes(s string, max int) string {
+ if max <= 0 {
+ return s
+ }
+ runes := []rune(s)
+ if len(runes) <= max {
+ return s
+ }
+ if max <= 1 {
+ return string(runes[:max])
+ }
+ return string(runes[:max-1]) + "…"
+}
+
+func goRawSafe(s string) string {
+ return strings.ReplaceAll(s, "`", "'")
+}
diff --git a/internal/pipeline/dogfood.go b/internal/pipeline/dogfood.go
index fdc380bb..805f9a3f 100644
--- a/internal/pipeline/dogfood.go
+++ b/internal/pipeline/dogfood.go
@@ -337,11 +337,22 @@ func checkNovelFeatures(cliDir, researchDir string) NovelFeaturesCheckResult {
if err := WriteNovelFeaturesBuilt(researchDir, built); err != nil {
fmt.Fprintf(os.Stderr, "warning: could not write novel_features_built: %v\n", err)
} else {
- if err := SyncCLIManifestNovelFeatures(cliDir, built); err != nil {
+ if changed, err := SyncCLIManifestNovelFeatures(cliDir, built); err != nil {
fmt.Fprintf(os.Stderr, "warning: could not sync novel_features to CLI manifest: %v\n", err)
+ } else if changed {
+ fmt.Fprintln(os.Stderr, "dogfood: synced .printing-press.json (novel_features) from novel_features_built")
}
- if err := SyncCLITranscendenceDocs(cliDir, built); err != nil {
+ if artifacts, err := SyncCLITranscendenceDocs(cliDir, built); err != nil {
fmt.Fprintf(os.Stderr, "warning: could not sync transcendence docs: %v\n", err)
+ } else {
+ for _, artifact := range artifacts {
+ fmt.Fprintf(os.Stderr, "dogfood: synced %s (%s) from novel_features_built\n", artifact.Path, artifact.Detail)
+ }
+ }
+ if changed, err := SyncCLIRootHighlights(cliDir, built); err != nil {
+ fmt.Fprintf(os.Stderr, "warning: could not sync root highlights: %v\n", err)
+ } else if changed {
+ fmt.Fprintln(os.Stderr, "dogfood: synced internal/cli/root.go (Highlights) from novel_features_built")
}
}
diff --git a/internal/pipeline/dogfood_test.go b/internal/pipeline/dogfood_test.go
index 5b0a2787..b6b56ce4 100644
--- a/internal/pipeline/dogfood_test.go
+++ b/internal/pipeline/dogfood_test.go
@@ -1,6 +1,7 @@
package pipeline
import (
+ "io"
"os"
"path/filepath"
"runtime"
@@ -787,6 +788,27 @@ func newHealthCmd() *cobra.Command {
func newHealthCmd() *cobra.Command {
return &cobra.Command{Use: "health"}
}`)
+ writeTestFile(t, filepath.Join(cliCodeDir, "root.go"), strings.Join([]string{
+ "package cli",
+ "",
+ "func newRootCmd() *cobra.Command {",
+ "\trootCmd := &cobra.Command{",
+ "\t\tUse: \"test-pp-cli\",",
+ "\t\tLong: `Test CLI",
+ "",
+ "Highlights (not in the official API docs):",
+ " • health planned health",
+ " • triage planned triage",
+ "",
+ "Agent mode: add --agent to any command for JSON output + non-interactive mode.",
+ "Health check: run 'test-pp-cli doctor' to verify auth and connectivity.",
+ "See README.md or the bundled SKILL.md for recipes.`,",
+ "\t}",
+ "\trootCmd.AddCommand(newHealthCmd())",
+ "\treturn rootCmd",
+ "}",
+ "",
+ }, "\n"))
writeTestFile(t, filepath.Join(cliDir, "README.md"), strings.Join([]string{
"# Test CLI",
"",
@@ -841,7 +863,10 @@ func newHealthCmd() *cobra.Command {
}
require.NoError(t, writeResearchJSON(research, researchDir))
- result := checkNovelFeatures(cliDir, researchDir)
+ var stderr string
+ result := captureStderr(t, &stderr, func() NovelFeaturesCheckResult {
+ return checkNovelFeatures(cliDir, researchDir)
+ })
assert.Equal(t, 1, result.Found)
assert.Equal(t, []string{"triage"}, result.Missing)
@@ -865,6 +890,15 @@ func newHealthCmd() *cobra.Command {
assert.Contains(t, skill, "**`health`**")
assert.NotContains(t, skill, "triage")
assert.Less(t, strings.Index(skill, "## Unique Capabilities"), strings.Index(skill, "## Command Reference"))
+
+ rootData, err := os.ReadFile(filepath.Join(cliCodeDir, "root.go"))
+ require.NoError(t, err)
+ root := string(rootData)
+ assert.Contains(t, root, "Highlights (not in the official API docs):")
+ assert.Contains(t, root, "health See scheduling health metrics at a glance")
+ assert.NotContains(t, root, "planned health")
+ assert.NotContains(t, root, "triage")
+ assert.Contains(t, stderr, "dogfood: synced internal/cli/root.go (Highlights) from novel_features_built")
})
t.Run("inserts README and SKILL sections when absent", func(t *testing.T) {
@@ -965,6 +999,24 @@ func TestCheckNovelFeatures_ZeroSurvivors(t *testing.T) {
cliCodeDir := filepath.Join(cliDir, "internal", "cli")
require.NoError(t, os.MkdirAll(cliCodeDir, 0o755))
// No command files — nothing registered
+ writeTestFile(t, filepath.Join(cliCodeDir, "root.go"), strings.Join([]string{
+ "package cli",
+ "",
+ "func newRootCmd() *cobra.Command {",
+ "\treturn &cobra.Command{",
+ "\t\tUse: \"test-pp-cli\",",
+ "\t\tLong: `Test CLI",
+ "",
+ "Highlights (not in the official API docs):",
+ " • health planned health",
+ "",
+ "Agent mode: add --agent to any command for JSON output + non-interactive mode.",
+ "Health check: run 'test-pp-cli doctor' to verify auth and connectivity.",
+ "See README.md or the bundled SKILL.md for recipes.`,",
+ "\t}",
+ "}",
+ "",
+ }, "\n"))
writeTestFile(t, filepath.Join(cliDir, "README.md"), strings.Join([]string{
"# Test CLI",
"",
@@ -1027,6 +1079,30 @@ func TestCheckNovelFeatures_ZeroSurvivors(t *testing.T) {
require.NoError(t, err)
assert.NotContains(t, string(skillData), "## Unique Capabilities")
assert.Contains(t, string(skillData), "## Command Reference")
+
+ rootData, err := os.ReadFile(filepath.Join(cliCodeDir, "root.go"))
+ require.NoError(t, err)
+ assert.NotContains(t, string(rootData), "Highlights (not in the official API docs):")
+ assert.NotContains(t, string(rootData), "planned health")
+}
+
+func captureStderr[T any](t *testing.T, captured *string, fn func() T) T {
+ t.Helper()
+
+ old := os.Stderr
+ r, w, err := os.Pipe()
+ require.NoError(t, err)
+ os.Stderr = w
+
+ result := fn()
+
+ require.NoError(t, w.Close())
+ os.Stderr = old
+ out, err := io.ReadAll(r)
+ require.NoError(t, err)
+ require.NoError(t, r.Close())
+ *captured = string(out)
+ return result
}
func TestDeriveDogfoodVerdict_NovelFeatures(t *testing.T) {
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 0182fc19..3f40c500 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -2137,12 +2137,12 @@ Fix order (update heartbeat between each fix category to prevent stale lock duri
5. missing novel features (see below)
6. scorecard-only polish gaps
-**Missing novel features fix (step 5):** Dogfood writes `novel_features_built` to research.json — only features whose commands actually exist. The original `novel_features` (aspirational list from absorb) is preserved for the audit trail. Dogfood also syncs the generated `README.md` `## Unique Features` block and `SKILL.md` `## Unique Capabilities` block from `novel_features_built`; if none survived, it removes those blocks. After dogfood:
+**Missing novel features fix (step 5):** Dogfood writes `novel_features_built` to research.json — only features whose commands actually exist. The original `novel_features` (aspirational list from absorb) is preserved for the audit trail. Dogfood also syncs the generated `.printing-press.json` `novel_features`, `README.md` `## Unique Features` block, `SKILL.md` `## Unique Capabilities` block, and `internal/cli/root.go` `--help` Highlights block from `novel_features_built`; if none survived, it removes the rendered README/SKILL/root help blocks. Dogfood prints `dogfood: synced ... from novel_features_built` for every rendered artifact it changes. After dogfood:
1. Inspect the dogfood planned-vs-built delta
2. Build missing approved features when they are still in scope
-3. Rerun dogfood so research.json, `.printing-press.json`, README.md, and SKILL.md are all synced from the verified set
-4. Audit surrounding README/SKILL prose, recipes, trigger phrases, and examples for indirect references to dropped features
+3. Rerun dogfood so research.json, `.printing-press.json`, README.md, SKILL.md, and root `--help` Highlights are all synced from the verified set
+4. Audit surrounding README/SKILL/root help prose, recipes, trigger phrases, and examples for indirect references to dropped features
5. Log which features were dropped (planned vs built delta)
After fixing each category, update the heartbeat:
diff --git a/testdata/golden/expected/dogfood-novel-doc-sync/stderr.txt b/testdata/golden/expected/dogfood-novel-doc-sync/stderr.txt
index e69de29b..3e79cd96 100644
--- a/testdata/golden/expected/dogfood-novel-doc-sync/stderr.txt
+++ b/testdata/golden/expected/dogfood-novel-doc-sync/stderr.txt
@@ -0,0 +1,3 @@
+dogfood: synced .printing-press.json (novel_features) from novel_features_built
+dogfood: synced README.md (Unique Features) from novel_features_built
+dogfood: synced SKILL.md (Unique Capabilities) from novel_features_built
← 96dd07c0 fix(cli): session_handshake auth correctness pass (#534)
·
back to Cli Printing Press
·
fix(cli): dry-run narrative examples in strict validation (# e4e66bd3 →