Skip to content

feat(#1512): remove abandoned generated documentation files#3383

Open
fullsend-ai-coder[bot] wants to merge 3 commits into
mainfrom
agent/1512-abandoned-doc-removal
Open

feat(#1512): remove abandoned generated documentation files#3383
fullsend-ai-coder[bot] wants to merge 3 commits into
mainfrom
agent/1512-abandoned-doc-removal

Conversation

@fullsend-ai-coder

Copy link
Copy Markdown

Add cleanup logic to the documentation generation process that removes stale generated .adoc files when their corresponding CLI commands, Rego builtins, or Tekton tasks are removed.

Each documentation template now includes a generated-file marker comment at the top of each output file. The GenerateAsciidoc function collects all file paths written by the CLI, Rego, and Tekton generators, then scans the pages directory for .adoc files with the marker that were not produced in the current run. These stale files are removed automatically. Handwritten documentation files (which lack the marker) are never touched.

The generator functions (GenerateCommandLineDocumentation, GenerateRegoReference, GenerateTektonDocumentation) now return the list of page file paths they wrote, enabling the cleanup logic in the parent GenerateAsciidoc function.


Closes #1512

Post-script verification

  • Branch is not main/master (agent/1512-abandoned-doc-removal)
  • Secret scan passed (gitleaks — d134e495b18cf8493cfea8791e310b58f0320797..HEAD)
  • Pre-commit hooks passed (authoritative run on runner)
  • Tests ran inside sandbox

Add cleanup logic to the documentation generation process that removes
stale generated .adoc files when their corresponding CLI commands, Rego
builtins, or Tekton tasks are removed.

Each documentation template now includes a generated-file marker comment
at the top of each output file. The GenerateAsciidoc function collects
all file paths written by the CLI, Rego, and Tekton generators, then
scans the pages directory for .adoc files with the marker that were not
produced in the current run. These stale files are removed automatically.
Handwritten documentation files (which lack the marker) are never
touched.

The generator functions (GenerateCommandLineDocumentation,
GenerateRegoReference, GenerateTektonDocumentation) now return the list
of page file paths they wrote, enabling the cleanup logic in the parent
GenerateAsciidoc function.

Closes #1512
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:55 AM UTC · Completed 10:06 AM UTC
Commit: 47d3320 · View workflow run →

@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 28.15534% with 74 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/documentation/asciidoc/rego/rego.go 0.00% 27 Missing ⚠️
internal/documentation/asciidoc/tekton/tekton.go 0.00% 18 Missing ⚠️
internal/documentation/asciidoc/asciidoc.go 65.90% 15 Missing ⚠️
internal/documentation/asciidoc/cli/cli.go 0.00% 14 Missing ⚠️
Flag Coverage Δ
acceptance 53.44% <ø> (+<0.01%) ⬆️
generative 16.59% <0.00%> (-0.20%) ⬇️
integration 27.34% <0.00%> (-0.32%) ⬇️
unit 68.56% <28.15%> (-0.57%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/documentation/asciidoc/cli/cli.go 0.00% <0.00%> (ø)
internal/documentation/asciidoc/asciidoc.go 59.18% <65.90%> (+59.18%) ⬆️
internal/documentation/asciidoc/tekton/tekton.go 0.00% <0.00%> (ø)
internal/documentation/asciidoc/rego/rego.go 0.00% <0.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review

Verdict: approve

Clean, well-structured implementation that correctly addresses #1512. All prior review feedback (marker duplication, premature append, defer-in-loop, logging, error-path test coverage) has been resolved across the three commits.

Correctness

The cleanup logic in removeAbandonedPages is sound:

  • Builds a set of paths produced by the current generation run
  • Scans the pages/ directory for .adoc files with the GeneratedMarker as the first line
  • Removes only files that have the marker AND were not produced in the current run
  • Handwritten files (no marker) are never touched

The GeneratedMarker constant is the single source of truth — written programmatically via fmt.Fprintln before template execution, not embedded in template files. This eliminates the marker-drift risk noted in earlier review rounds.

The deferred-close-in-loop fix in rego.go and tekton.go (commit 2) correctly replaces defer f.Close() inside loops with explicit f.Close() calls, preventing file handle accumulation.

The append-after-Execute fix in cli.go (commit 3) ensures failed template executions don't leave paths in the generated list.

Path construction is consistent between generators (filepath.Join(module, "pages", ...)) and the cleanup scanner (filepath.Join(pagesDir, entry.Name())), so the set lookup will match correctly.

GenerateAsciidoc signature (func GenerateAsciidoc(module string) error) is unchanged, so the only caller in documentation.go continues to work. The internal sub-package function signature changes (GenerateCommandLineDocumentation, GenerateRegoReference, GenerateTektonDocumentation) are confined to this package.

Tests cover: stale file removal, handwritten file preservation, non-adoc file preservation, mixed scenarios, empty directory, non-existent directory error path, and the hasGeneratedMarker helper.

Security

No concerns. The function operates exclusively on .adoc files within a known directory structure using os.ReadDir + filepath.Join (no path traversal vectors). The marker is a hardcoded constant, not user input.

Intent & coherence

The change precisely matches the scope described in #1512: detect and remove stale generated documentation files when the corresponding CLI commands, Rego builtins, or Tekton tasks are removed. The marker-based approach is a sensible choice — it's simple, deterministic, and leaves handwritten documentation untouched.

Style / conventions

Follows project conventions: proper error wrapping with %w, //go:build unit tag on tests, testify assertions, Apache 2.0 license headers, and stderr logging for operational visibility.

Previous run

Review — approve

Clean, well-structured implementation of stale generated-doc cleanup for #1512. The marker-based approach is sound, the code is correct, and the tests cover the important scenarios.

What the PR does

  1. Marker comment — adds // Generated by conforma CLI documentation tooling. DO NOT EDIT. (an AsciiDoc single-line comment, invisible in rendered output) as the first line of every generated .adoc file via template changes in cli.tmpl, rego.tmpl, builtins.tmpl, and task.tmpl.
  2. Return generated pathsGenerateCommandLineDocumentation, GenerateRegoReference, and GenerateTektonDocumentation now return []string of written page paths.
  3. Cleanup passremoveAbandonedPages scans pages/, identifies .adoc files whose first line matches the marker but are not in the current-run generated set, and removes them. Handwritten files (no marker) are left untouched.
  4. Incidental fixdefer f.Close() inside for loops in rego.go and tekton.go replaced with explicit f.Close() after template execution, fixing a pre-existing resource-leak pattern.
  5. Tests — new asciidoc_test.go covers stale removal, handwritten preservation, non-.adoc preservation, mixed scenarios, empty directory, and marker detection.

Reviewed dimensions

Dimension Result
Correctness ✅ Path construction is consistent across generators and cleanup. Template marker placement verified (including rego.tmpl {{- -}} whitespace trimming). hasGeneratedMarker correctly reads only the first line. Error propagation is sound.
Security ✅ No concerns — cleanup operates within the controlled pages/ directory, filepath.Join prevents traversal, no user-controlled input flows into paths.
Intent & coherence ✅ Matches issue #1512 exactly. Appropriately scoped — only adds the cleanup mechanism, doesn't refactor unrelated code (the defer fix is a natural consequence of the loop changes).
Style & conventions ✅ Follows project Go conventions: %w error wrapping, testify assertions, proper license headers, //go:build unit tag.
Documentation ✅ The marker comment itself serves as in-file documentation. PR body clearly explains the approach.
Cross-repo contracts ✅ No external API changes. Return type changes are internal.

Findings

[low] pre-existing-orphan — docs/modules/ROOT/pages/verify-conforma-vsa-release-ta.adoc

This file is an existing orphaned Tekton task document — the corresponding task YAML (tasks/verify-conforma-vsa-release-ta/) has been removed, but the .adoc page was left behind. Because it was generated before the marker was introduced, it lacks the GeneratedMarker on line 1 and the new cleanup mechanism will treat it as a handwritten file, leaving it in place indefinitely.

This is a one-time bootstrap gap, not a flaw in the mechanism — all future removals will be handled correctly. Consider deleting this file in a follow-up commit or PR.

Previous run (2)

Review — approve

Clean implementation of stale generated-doc cleanup for #1512. The marker-based approach is sound: each template now embeds a // Generated by conforma CLI documentation tooling. DO NOT EDIT. comment as the first line of output, the three generator functions (GenerateCommandLineDocumentation, GenerateRegoReference, GenerateTektonDocumentation) return the list of page paths they wrote, and removeAbandonedPages scans the pages/ directory and removes only .adoc files whose first line matches the marker but which were not part of the current generation run. Handwritten files are never touched.

Correctness

  • Path consistency ✅ — All generators construct paths as filepath.Join(module, "pages", <filename>) and the cleanup function reconstructs paths identically from os.ReadDir entries. Confirmed matching.
  • Recursive CLI path tracking ✅ — generateCommandReference uses a *[]string accumulator passed through recursive calls, so subcommand page paths are correctly collected at all levels.
  • rego.tmpl marker placement ✅ — The marker is placed after {{define}} blocks, which produce no rendered output. The trailing -}} trim markers on the last define block consume the intervening whitespace, so the marker is the first character of rendered output.
  • Nav files excluded ✅ — Nav files are written to partials/, not pages/, so they are correctly excluded from the generated-paths list and from the cleanup scan.
  • GenerateAsciidoc signature unchanged ✅ — The public function signature remains error, so the caller in documentation.go is unaffected.
  • Tests ✅ — Good coverage of the main scenarios: stale removal, handwritten preservation, non-adoc file skipping, mixed scenario, empty directory, and marker detection (with marker, without marker, empty file).

Security

No security findings. The code operates on a known local directory using safe Go standard library APIs (os.ReadDir, os.Open, os.Remove). DirEntry.Name() cannot contain path separators, so path traversal via filepath.Join is not possible. os.Remove on symlinks removes the link, not the target. All changes are in internal/ packages with no external API surface.

Scope & coherence

The PR precisely addresses issue #1512's request: "The document generation code should keep track of any abandoned components and remove the corresponding Asciidoc files." No scope creep — all changes serve the cleanup feature. The marker-based approach is a pragmatic choice that is safe by default (only deletes files it can positively identify as generated).

Notes

  • Pre-existing defer f.Close() in loops — Both generateRegoReference (rego.go) and generateTektonReference (tekton.go) use defer f.Close() inside for loops. Since defer executes at function return (not loop iteration end), all file handles opened during the loop remain open simultaneously. With the small number of builtins and tasks this is unlikely to cause issues, but it is a well-known Go anti-pattern worth fixing as follow-up.
  • Pre-existing orphanverify-conforma-vsa-release-ta.adoc exists in the pages directory but has no corresponding task YAML in tasks/. Since it was generated before the marker system, it lacks the marker and will not be auto-cleaned. This is the correct safe behavior — the cleanup mechanism works going forward for newly-generated files. A one-time manual deletion could address this specific file.

Labels: PR modifies documentation generation tooling and generated docs

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge documentation Improvements or additions to documentation labels Jul 6, 2026
@st3penta

st3penta commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Jul 7, 2026

Copy link
Copy Markdown
Author

🤖 Finished Fix · ✅ Success · Started 12:32 PM UTC · Completed 12:53 PM UTC
Commit: 7c8ccca · View workflow run →

Replace defer f.Close() with explicit f.Close() calls in
generateRegoReference and generateTektonReference to prevent
file handle accumulation during loop iterations.

Addresses review feedback on #3383
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:53 PM UTC · Completed 1:00 PM UTC
Commit: 7c8ccca · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels Jul 7, 2026

// GeneratedMarker is the comment placed at the top of generated Asciidoc files
// to distinguish them from handwritten documentation.
const GeneratedMarker = "// Generated by conforma CLI documentation tooling. DO NOT EDIT."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This marker string is duplicated independently in the Go constant here and in 4 template files (cli.tmpl, rego.tmpl, builtins.tmpl, task.tmpl). If either side drifts, hasGeneratedMarker silently stops matching and stale files accumulate. No test catches this because the tests use the constant directly, never the rendered template output.

Consider injecting the marker via a template function (e.g. {{ generatedMarker }}) so the string lives in one place. That way the constant is the single source of truth and template drift is impossible.

Comment on lines 96 to 98
*generated = append(*generated, docpath)

return commandTemplate.Execute(f, cmd)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appends docpath to the generated list before commandTemplate.Execute runs. In rego.go and tekton.go, the append happens after Execute succeeds. If Execute fails here, the path ends up in the generated list anyway, so removeAbandonedPages will skip the file even though it wasn't written correctly.

Worth matching the pattern used by the other two generators: append after Execute.

{{- end }}{{- /* range */ -}}
{{- end -}}{{- /* "properties" */ -}}

// Generated by conforma CLI documentation tooling. DO NOT EDIT.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test renders any template and verifies its first output line matches GeneratedMarker. This is especially risky here in rego.tmpl where the marker sits on line 42 of the template source, relying on whitespace trimming to land it at the start of the rendered output. If that trimming behavior changes, the marker moves and hasGeneratedMarker stops matching.

I know this is arguably out of scope, but since you're already modifying this rarely-touched code, a test that renders each template and asserts the first line matches the constant would catch future drift and would leave this code better than you found it.

Comment on lines +98 to +100
if err := os.Remove(path); err != nil {
return fmt.Errorf("removing abandoned file %q: %w", path, err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deletes files with no logging. If a handwritten file is mistakenly detected as generated (e.g. someone copies the marker line into a doc), it vanishes with no trace.

A simple stderr log after a successful removal would leave a breadcrumb:

Suggested change
if err := os.Remove(path); err != nil {
return fmt.Errorf("removing abandoned file %q: %w", path, err)
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("removing abandoned file %q: %w", path, err)
}
fmt.Fprintf(os.Stderr, "Removed abandoned generated file: %s\n", path)

Comment on lines +73 to +76
entries, err := os.ReadDir(pagesDir)
if err != nil {
return fmt.Errorf("reading pages directory %q: %w", pagesDir, err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The os.ReadDir error path here has no test coverage. A test that passes a non-existent pagesDir (e.g. a module path where pages/ doesn't exist) would exercise it and confirm the error wrapping works as expected.

@st3penta

st3penta commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Jul 7, 2026

Copy link
Copy Markdown
Author

🤖 Finished Fix · ✅ Success · Started 3:49 PM UTC · Completed 4:16 PM UTC
Commit: 7c8ccca · View workflow run →

- Eliminate marker duplication: remove hardcoded marker from all 4
  templates (cli.tmpl, rego.tmpl, builtins.tmpl, task.tmpl) and write
  it programmatically via fmt.Fprintln before template execution. The
  GeneratedMarker constant is now the single source of truth, passed
  as a parameter to each generator function.
- Fix premature append in cli.go: move generated-path append after
  successful commandTemplate.Execute so failed writes do not appear
  in the generated list.
- Add logging on abandoned file removal: emit a message to stderr
  after each successful os.Remove in removeAbandonedPages.
- Add test for os.ReadDir error path: verify removeAbandonedPages
  returns an error when the pages directory does not exist.

Addresses review feedback on #3383
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:17 PM UTC · Completed 4:22 PM UTC
Commit: 7c8ccca · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation ready-for-merge All reviewers approved — ready to merge size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Abandoned documentation removal

1 participant