Skip to content

fix(ops): every growth/ops exporter honors --help without touching tracked or retired artifacts - #56

Closed
nish3451 wants to merge 5 commits into
mainfrom
fix/lane1-operator-export-cli-help-all
Closed

fix(ops): every growth/ops exporter honors --help without touching tracked or retired artifacts#56
nish3451 wants to merge 5 commits into
mainfrom
fix/lane1-operator-export-cli-help-all

Conversation

@nish3451

Copy link
Copy Markdown
Collaborator

Closes the [unreviewed-by-grok] item: Growth/ops exporters ignore --help and overwrite tracked ops artifacts (live-metrics, proof-library).

Problem

node scripts/export-growth-metrics.mjs --help ignored --help, ran the full export, and overwrote the tracked growth-brain/ops/live-metrics.md (same for proof-library.md and every other exporter). Eight more scripts in scripts/ still ignored --help and ran their entire export when asked for help — including export-full-stack-growth-map / export-owned-*, which recreate retired growth-brain/ops/ artifacts the active operator-surface contract requires to never exist.

Fix (3 commits)

  1. Active export surface (21 npm-backed exporters): every script now calls handleHelp() before any work — --help/-h prints usage and exits 0 without writing. All operator-supplied output paths (--output, --html, --ops, --loom-links) are resolved against the repo root via resolveOutputPath() and refused when they escape via absolute paths, .. traversal, or (dangling) symlinks. Shared helpers in scripts/lib/operator-cli.mjs.
  2. Remaining 8 export scripts (retired-artifact writers full-stack-growth-map, owned-handoff-loom-cockpit, owned-product-case-studies, owned-product-workflow-proofs; owned-startup proof capture; client channel-readiness / repeatable-workflow / weekly-report): same --help contract; the 5 with --output/--html flags also refuse escaping output paths.
  3. Test: test-active-operator-surfaces.mjs now asserts the --help/-h contract for all 29 export scripts, that no retired broad-service artifact is recreated by --help/-h, that export-owned-startup-proof-capture does not seed owned client folders on --help, and that the owned/client writers refuse escaping output paths.

Verification

  • npm run ci — full gate passes (all suites, 0 failures; node --check on every script)
  • Empirical check in a clean clone: every one of the 29 exporters run with --help prints usage, exits 0, and leaves the working tree byte-identical.

Supersedes the earlier partial PRs for this item (#36, #44, #55); this branch is the complete pass over all 29 export scripts based on fresh origin/main.

…-repo output paths

Every active operator export script now handles --help/-h before doing any
work: it prints usage and exits 0 without writing or overwriting any cockpit
or mission artifact. Operator-supplied output paths (--output, --html, --ops,
--loom-links) are resolved against the service repository root and refused
when they escape it via absolute paths, .. traversal, or symlinks -- including
dangling symlinks whose target writeFileSync would silently create outside
the repo -- so an export can no longer write or overwrite files anywhere.

- Add scripts/lib/operator-cli.mjs with handleHelp() and resolveOutputPath()
- Wire both into all 21 npm-script-backed export scripts; validate every
  output path before any dependency exporter runs or any artifact is written
- Route the internal-dashboard parity scratch inside the repo (unique
  runs/ path, cleaned up in finally) instead of /tmp
- Extend test-active-operator-surfaces.mjs: --help and -h contract for every
  active export script (exit 0 + usage + untouched artifacts), escape probes
  confined to a test-owned tmp directory, and symlink/dangling-symlink
  refusal probes
…wth/ops artifacts stay untouched

The first pass covered the 21 npm-backed active exporters. Eight scripts in
scripts/ still ignored --help and ran their full export when asked for help:

- export-full-stack-growth-map, export-owned-handoff-loom-cockpit,
  export-owned-product-case-studies, export-owned-product-workflow-proofs
  recreate retired growth-brain/ops artifacts (owned-*, full-stack-growth-map.*)
  that the active operator surface contract requires to never exist
- export-owned-startup-proof-capture seeds owned client folders and rewrites
  client proof packets
- export-client-channel-readiness, export-client-repeatable-workflow,
  export-client-weekly-report rewrite client runtime scorecards and reports

All eight now call handleHelp() before any work: --help/-h prints usage and
exits 0 without writing. The three owned-* writers and the two client writers
with --output/--html flags also route their output paths through
resolveOutputPath() so an operator-supplied path can no longer escape the
repository.

test-active-operator-surfaces.mjs now asserts the --help/-h contract for all
29 export scripts, that no retired broad-service artifact is recreated by
--help/-h, that export-owned-startup-proof-capture does not seed owned client
folders on --help, and that the owned-*/client writers refuse escaping output
paths.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@nish3451, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d7c683e7-52f7-4277-a97c-bf3c20a049f3

📥 Commits

Reviewing files that changed from the base of the PR and between 623576d and 49436b2.

📒 Files selected for processing (31)
  • scripts/export-client-channel-readiness.mjs
  • scripts/export-client-delivery-cockpit.mjs
  • scripts/export-client-repeatable-workflow.mjs
  • scripts/export-client-weekly-report.mjs
  • scripts/export-daily-money-mission.mjs
  • scripts/export-followup-cockpit.mjs
  • scripts/export-full-stack-growth-map.mjs
  • scripts/export-growth-cockpit.mjs
  • scripts/export-growth-doctor.mjs
  • scripts/export-growth-metrics.mjs
  • scripts/export-internal-dashboard.mjs
  • scripts/export-lead-scoring-cockpit.mjs
  • scripts/export-managed-it-one-pager.mjs
  • scripts/export-market-benchmark.mjs
  • scripts/export-market-learning-review.mjs
  • scripts/export-market-proof-cockpit.mjs
  • scripts/export-market-proof-run.mjs
  • scripts/export-owned-handoff-loom-cockpit.mjs
  • scripts/export-owned-product-case-studies.mjs
  • scripts/export-owned-product-workflow-proofs.mjs
  • scripts/export-owned-startup-proof-capture.mjs
  • scripts/export-proof-library.mjs
  • scripts/export-prospect-outbox.mjs
  • scripts/export-recording-cockpit.mjs
  • scripts/export-recording-queue.mjs
  • scripts/export-recording-rehearsal-check.mjs
  • scripts/export-recording-teleprompter.mjs
  • scripts/export-sales-cockpit.mjs
  • scripts/export-sender-setup-guide.mjs
  • scripts/lib/operator-cli.mjs
  • scripts/test-active-operator-surfaces.mjs

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2071d9e97f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
}
}
return resolved;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep exported artifact paths repository-relative

Returning resolved changes every caller that reuses the write path in its JSON or generated content from a repository-relative path to an absolute host path. For example, a normal metrics export now reports /workspace/.../growth-brain/ops/live-metrics.md, and export-internal-dashboard.mjs embeds those absolute values in its dashboard, making artifacts machine-specific and exposing temporary checkout paths in tests. Preserve the raw repository-relative value for output and reporting while using the resolved value only for filesystem operations, as export-market-benchmark.mjs already does.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 49436b273a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// that a dangling symlink -- one whose target writeFileSync would silently
// create outside the repository -- is caught as well as a live one.
export function resolveOutputPath(value, { flag = "--output", fallback } = {}) {
const raw = value === undefined || value === null || value === "" ? fallback : value;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject explicit empty output values

When an output option is supplied with an empty value—for example, npm run growth:metrics -- --output="$UNSET" when the variable is unset—this treats it as though the option were omitted and silently writes the fallback path. For exporters whose fallback is tracked, that unexpectedly overwrites artifacts such as growth-brain/ops/live-metrics.md; before this change, writing to the empty filename failed instead. Reserve the fallback for undefined/null and refuse an explicitly empty value.

Useful? React with 👍 / 👎.

nish3451 added a commit that referenced this pull request Aug 11, 2026
The fleet keeps dispatching the same finding to multiple lanes, producing
duplicate same-fix PR pairs: #36/#44 and #55/#56 are byte-identical or
near-identical patches of the operator export --help fix, #39/#49 the
offername article fix, #40/#52 the recording exporter --help fix, plus
#38/#48/#51, #30/#61/#72, #45/#64, #42/#60, #43/#54 and #46/#74.

Add a PR Duplicate Guard:
- scripts/check-pr-duplicates.mjs compares a PR's diff against every other
  open PR (shared changed-file coverage >= 0.8 and patch similarity >= 0.5).
  Calibrated on all 79 open PRs on 2026-08-11: every pair above the
  thresholds was a genuine duplicate-cluster member, zero false positives.
- .github/workflows/pr-duplicate-guard.yml runs it on every PR event and
  posts one marker comment naming the duplicate(s) and the canonical PR; the
  check fails loudly when a duplicate is found. Informational, not required.
- scripts/test-pr-duplicates.mjs covers parsing, similarity, detection, and
  comment upsert with an injected API; wired into npm ci and npm test.
@nish3451

Copy link
Copy Markdown
Collaborator Author

Closing in favour of #160 — superseded by main itself.

This PR rewrites all 29 operator/growth exporters plus scripts/lib/operator-cli.mjs. Since it was opened (2026-08-10), main has independently landed the shared operator-cli.mjs helper and wired 18 of the 29 exporters to it, using a different and now-canonical implementation. That is why this PR conflicts in 12 files, including operator-cli.mjs itself — it would revert main's newer version of the helper (lstatSync-based symlink refusal vs this branch's older existsSync form) and re-apply an older calling convention to 18 exporters that are already done.

The only genuinely outstanding work is the 11 exporters still unwired on main, and #160 covers exactly those 11 against the current helper. Landing #160 completes the cluster; landing this would be a large conflicted revert.

Note: I earlier closed #36, #44, #55, #98, #40, #52 and #95 citing this PR as the keeper. That attribution was wrong and I have corrected it on each of them — the keeper for this cluster is #160.

@nish3451 nish3451 closed this Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant