Skip to content

feat: Wire all programs to org profile (org portability PR B) - #47

Open
rubambiza wants to merge 16 commits into
rossoctl:mainfrom
rubambiza:feat/org-profile-rewire
Open

feat: Wire all programs to org profile (org portability PR B)#47
rubambiza wants to merge 16 commits into
rossoctl:mainfrom
rubambiza:feat/org-profile-rewire

Conversation

@rubambiza

Copy link
Copy Markdown
Contributor

Summary

PR B ("rewire") of the org-portability refactor. Wires all seven scanner/fixer programs to the load_org_profile() seam introduced in PR A (#43) so the suite targets any GitHub org via one committed profile file, and completes the kagenti→rossoctl rename as the first consumer.

Every program now resolves its org identity by precedence --flag > env > profile > default (ORG, FORK_OWNER, MAIN_REPO, REPOS_DIR, SOURCE_REPO, plus the transitional REMAP). No org name is hardcoded in a read or write path; the default profile (config/org.env) supplies rossoctl.

What changed

Rewire (Tasks 5–9):

  • dep-bump-scanner, dep-bump-fixer, pr-review-scanner, pr-review-impact, link-health-scanner, link-health-fixer wired to the loader; --org/--fork-owner/--repos-dir/--profile flags added where missing.
  • automation-health-dashboard newly sources program-lib.sh; --kagenti-dir/KAGENTI_DIR renamed to --main-repo-dir/MAIN_REPO_DIR (old flag kept as a deprecated, warning alias).
  • Fixed a silent prefix bug in link-health-fixer (${repo#"$ORG/"}${repo##*/}): the $ORG-coupled strip failed when ORG ≠ the repo owner.

Report home (#44):

  • The org main repo's docs/ now feeds the docs site and cannot host machine reports, so both standing report PRs (link-health, dashboard) write a single perpetual file under automation-health/ in this repo, overwritten in place each run. History is reconstructed from git commit history — no dated snapshots. Added automation-health/README.md documenting the convention.

Auditability:

  • Report PRs are branded and carry an "Automation program" section linking back to the invoking program's standing order, via a new overridable SOURCE_REPO fact (default $ORG/automation).
  • Standing orders (standing-orders/*.md) synced with the rename, report destinations, epic refs, and pr-review scope; added standing-orders/repo-sync.md for the nightly clone-sync program.

Tests/docs (Task 10):

  • Portability smoke test proving a foreign-org profile yields <org>/* refs with no rossoctl/kagenti leak.
  • README "Org profile" section + "Adapting for a Different Org" workflow.

Verification

  • Full unit suite green (org-profile, core-repos, pr-review-integration, pr-review-impact, extract-broken-links, parse-diff-map).
  • Deployed and exercised live: the link-health and dashboard report PRs (docs: Link health report (auto-updated) #45, docs: Automation health dashboard (auto-updated) #46) push to automation-health/ here with correct cross-fork wiring and standing-order links.
  • Parity confirmed for the default rossoctl case (every read ref resolves to the same string as before the rewire).

Fixes #30
Closes #31

Notes for reviewers

Assisted-By: Claude Code

rubambiza added 14 commits July 31, 2026 16:59
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
The org main repo's docs/ folder now sources the docs site (rossoctl.dev),
which overwrites the machine-generated report files. Temporarily redirect the
standing link-health and automation-health report PRs to docs/reports/ in the
automation repo. Tracking: rossoctl#44 (ref rossoctl/rossoctl#2315).

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Wire the documented --profile <name> selector (and --org for the two
pr-review programs that lacked it) into each program's arg loop so the
profile can be chosen per invocation, matching README and the loader's
PROFILE_FLAG/ORG_FLAG precedence inputs.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
The live report-push path did an unconditional cd into
$REPORT_TARGET_DIR ($REPOS_DIR/automation) under set -e, with no
existence guard and no MAIN_REPO_DIR override, so a missing clone
would abort hard mid-run. Mirror the dashboard's guard: honor a
MAIN_REPO_DIR override and validate the dir is a git repo before
cd, failing loud with actionable guidance in live mode. Dry-run is
unaffected (it never cd's).

Whole-branch review finding (Important) for PR B.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
The link-scanner and dashboard header comments still read
'— kagenti org'. Both scripts are org-neutral now (org resolved
via profile), so drop the suffix rather than hardcode a new org.
Cosmetic; whole-branch review Minor finding.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Per rossoctl#44: the main repo docs/ feeds rossoctl.dev
and cannot host machine reports. Both standing report PRs (link-
health scanner + automation-health dashboard) now write a single
perpetual file under automation-health/ in the automation repo,
overwritten in place each run. Trends come from replaying git
commit history, so we store state (not dated snapshots) and avoid
the files-vs-diffs-on-Git anti-pattern.

- link-health-scanner:  automation-health/link-health.md
- dashboard:            automation-health/automation-health.md
- add automation-health/README.md documenting the convention

Supersedes the earlier docs/reports/ redirect; the dashboard PR
(previously accepted in the main repo) is redirected too for
consistency. Was TEMPORARY, now the settled home.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Bring the version-controlled standing orders in line with the
rewired scripts, the org rename, and the report-home decision so
the repo and the live schedule no longer diverge:

- org 'kagenti' -> active-org / rossoctl; drop hardcoded ~/kagenti
  clone paths in favor of 'the core repos, cloned locally'
- report destinations -> automation-health/{link-health,automation-
  health}.md in rossoctl/automation (single perpetual file; history
  via git commit history, rossoctl#44)
- epic/tracking refs -> rossoctl/rossoctl#1178/#1260/#1910
- pr-review scope -> the core allowlist (config/core-repos.txt)
- add standing-orders/repo-sync.md: the previously-untracked nightly
  clone-sync order, described in org/repo terms (no host detail)
- rename the dep-bump fixer signature Kagenti -> Rossoctl (also the
  dedup marker; documented one-time duplicate-comment cost)

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Report-PR bodies now identify the invoking program and link to its
standing order in the source repo, so a human reading the PR can
trace which automation program produced it.

- rename remaining Kagenti display strings -> Rossoctl (PR openers +
  report footers) for the link-health scanner and dashboard
- add a '## Automation program' section with a minimal inline link:
  Generated by the [Rossoctl <Program>](<standing-order-url>)
- add SOURCE_REPO to load_org_profile (flag/env/profile/default,
  default $ORG/automation): the repo where scripts/skills/standing
  orders live, used to build the standing-order URL portably so a
  fork points at its own automation repo without editing scripts
- document optional PROFILE_SOURCE_REPO in config/org.env
- gitignore .host-backup/ (local off-host copies of cron/job state)

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
@rubambiza rubambiza added the ready-for-ai-review Request automated AI code review from clawgenti label Aug 5, 2026
@rubambiza rubambiza self-assigned this Aug 5, 2026

@clawgenti clawgenti left a comment

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.

Solid org-portability rewire — the profile-seam abstraction is clean and the ${repo##*/} prefix-strip fix (#389) is correct. 14/14 commits are DCO signed-off and CI (DCO) passes.

Findings:

suggestion scripts/link-health-scanner.sh line 59 — FORK_REMOTE is still hardcoded "clawgenti-kagenti-fork". On an existing deployment this remote already exists in .git/config pointing at github.com/clawgenti/kagenti.git (the old report target). Because the git remote get-url guard at line 649 succeeds, the new URL (clawgenti/automation.git) is never registered and pushes silently land on the wrong repo. Consider renaming the constant (e.g. "$FORK_OWNER-automation-fork") or adding a remote-URL update step after the guard.

nit scripts/automation-health-dashboard.sh line 23 — MAIN_REPO_DIR is seeded from ${KAGENTI_DIR:-} as a migration alias. If KAGENTI_DIR is still set in the environment from an old deployment it will silently shadow the profile-derived REPOS_DIR/automation path. A one-time warning (echo "WARN: KAGENTI_DIR is deprecated" >&2) here would match the pattern used by --kagenti-dir at line 185.


Reviewed by clawgenti using github:pr-review

Comment thread scripts/link-health-scanner.sh Outdated
# else derive from REPOS_DIR.
REPORT_TARGET_DIR="${MAIN_REPO_DIR:-$REPOS_DIR/$REPORT_TARGET_NAME}"

FORK_REMOTE="clawgenti-kagenti-fork"

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.

suggestion: FORK_REMOTE is still hardcoded as "clawgenti-kagenti-fork". On an existing deployment this remote exists in .git/config pointing at github.com/clawgenti/kagenti.git (the old report target). The guard at the remote-add block (git remote get-url "$FORK_REMOTE") will succeed and skip re-registering the URL — pushes will land on the wrong repo. Either rename the constant to something like "$FORK_OWNER-automation-fork" (so old remotes don't collide), or add a URL-update step:

git remote set-url "$FORK_REMOTE" "https://github.com/$FORK_OWNER/${REPORT_TARGET_NAME}.git" 2>/dev/null || \
  git remote add "$FORK_REMOTE" "https://github.com/$FORK_OWNER/${REPORT_TARGET_NAME}.git"

Comment thread scripts/automation-health-dashboard.sh Outdated
SHOW_HELP=false
FORK_OWNER="${FORK_OWNER:-clawgenti}"
KAGENTI_DIR="${KAGENTI_DIR:-}"
MAIN_REPO_DIR="${MAIN_REPO_DIR:-${KAGENTI_DIR:-}}"

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.

nit: MAIN_REPO_DIR is seeded from ${KAGENTI_DIR:-} as a silent migration alias. If KAGENTI_DIR is still set in the environment from an old deployment, it will silently win over the profile-derived default, masking the new REPOS_DIR/automation path. A deprecation warning here would match the explicit one added for --kagenti-dir at line 185:

if [ -n "${KAGENTI_DIR:-}" ]; then
  echo "WARN: KAGENTI_DIR is deprecated; set MAIN_REPO_DIR instead" >&2
fi
MAIN_REPO_DIR="${MAIN_REPO_DIR:-${KAGENTI_DIR:-}}"

Address clawgenti review on rossoctl#47:

- link-health-scanner: drop the hardcoded 'clawgenti-kagenti-fork'
  FORK_REMOTE literal (now $FORK_OWNER-automation-fork, org-neutral).
- both report writers: register the fork remote with 'set-url || add'
  instead of guard-then-skip, so a stale remote left by a prior
  deployment (pointing at the old report repo) is corrected rather
  than silently pushed to the wrong target.
- dashboard: remove the KAGENTI_DIR env alias and the --kagenti-dir
  flag entirely. The host cron no longer passes either (Task 11
  switched it to --main-repo-dir), so the alias only guarded a
  scenario that no longer exists; --main-repo-dir/MAIN_REPO_DIR is
  now the sole interface, leaving no org-named knob.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
@rubambiza

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Both addressed in 55034e1:

suggestion (FORK_REMOTE) — dropped the hardcoded clawgenti-kagenti-fork literal; the remote name now derives from the profile ($FORK_OWNER-automation-fork). More importantly, both report writers now register the remote with git remote set-url ... || git remote add ... instead of the guard-then-skip, so a stale remote left by a prior deployment is corrected to the current target rather than silently pushing to the old repo. (Good catch — this is the same class of issue we hit during the controlled live run.)

nit (KAGENTI_DIR) — rather than warn, removed the alias entirely. The report jobs no longer pass KAGENTI_DIR (migrated to --main-repo-dir), so it only guarded a scenario that no longer exists. Both the KAGENTI_DIR env seed and the --kagenti-dir flag are gone; --main-repo-dir/MAIN_REPO_DIR is now the sole interface.

Assisted-By: Claude Code

@clawgenti clawgenti left a comment

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 latest commit (55034e14) fully addresses both prior review findings: FORK_REMOTE is now derived from $FORK_OWNER-automation-fork, and both report writers use set-url || add to correct stale remotes; KAGENTI_DIR/--kagenti-dir is removed entirely (not just warned against). All 15 commits are DCO signed-off, CI passes, and no residual org literals remain in the rewired code paths.

All checks pass. Ready for human review.


Reviewed by clawgenti using github:pr-review

@rubambiza rubambiza added ready-for-human-review AI review passed, ready for human reviewer and removed ready-for-ai-review Request automated AI code review from clawgenti labels Aug 6, 2026

@cwiklik cwiklik 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.

PR B of the org-portability refactor — wires all seven programs to the load_org_profile() seam and completes the kagenti→rossoctl rename. Clean, well-decomposed (15 commits), and it lands the design from #42 well.

Verified:

  • Each program calls load_org_profile exactly once — the rewire is uniform (dep-bump scanner/fixer, pr-review scanner/impact, link-health scanner/fixer, health-dashboard).
  • No hardcoded org identifiers remain in read/write paths — the only kagenti/rossoctl literals added are human-facing branding strings and the portability test's leak-guard.
  • Clobber-safety (my note on #42): the profile uses PROFILE_*-prefixed vars, so ORG="${ORG_FLAG:-${ORG:-${PROFILE_ORG:-}}}" can't be clobbered by a sourced profile — and the smoke test explicitly asserts a testorg profile yields testorg/* with no rossoctl/kagenti leak.
  • SOURCE_REPO added with the same --flag > env > PROFILE_* > default idiom and exported.

DCO green (all commits signed), no .claude/.vscode.

One non-blocking maintainer note: the behavior-changing part is the report-PR redirect (dashboard/link-health now land reports under automation-health/ in MAIN_REPO, PRs linking back to SOURCE_REPO standing orders). That's the one path the org-profile unit test doesn't cover, and these programs open real PRs against live repos — worth a --dry-run parity confirmation (per the spec's rollout step) before the first live run against rossoctl. Also minor: SOURCE_REPO is a new identity fact beyond the #42 spec's original set — worth a one-line addendum there for traceability.

LGTM.

Assisted-By: Claude Code

@evaline-ju evaline-ju 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.

lgtm, few non-blocking nits

Comment thread scripts/automation-health-dashboard.sh Outdated
Comment on lines +459 to +462
if [ -z "$REPORT_TARGET_DIR" ]; then
echo "ERROR: report target clone dir is not set (required for live mode)."
echo "Export MAIN_REPO_DIR or set REPOS_DIR so $REPORT_TARGET_REPO can be found:"
echo " export MAIN_REPO_DIR=$REPOS_DIR/$REPORT_TARGET_NAME"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

L86 sets this now, so this appears to be dead code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this guard is still valid against cases where neither MAIN_REPORT_DIR was exported when calling the script nor was REPOS_DIR set, in which case L86 may have derived nothing or garbage.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm not quite understanding. From the way L86 forms variables, I don't think it can derive empty especially with the L81 fallback, and a garbage case would not fall into this branch anyway with the emptiness guard (L459)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, and my earlier reply was off. REPORT_TARGET_DIR falls back to $REPOS_DIR/$REPORT_TARGET_NAME, and $REPORT_TARGET_NAME is always non-empty ("automation"), so the string is never empty — an unset REPOS_DIR would abort earlier under set -u, and a garbage path is non-empty and correctly caught by the .git check. Removed the dead -z guard in f7d006a and folded the actionable "export MAIN_REPO_DIR" hint into the surviving .git existence check. Thanks for the catch.

Comment thread scripts/link-health-scanner.sh Outdated
Comment on lines +456 to +461
if [ -z "$REPORT_TARGET_DIR" ]; then
echo "ERROR: report target clone dir is not set (required for live mode)."
echo "Export MAIN_REPO_DIR or set REPOS_DIR so $REPORT_TARGET_REPO can be found:"
echo " export MAIN_REPO_DIR=$REPOS_DIR/$REPORT_TARGET_NAME"
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

same dead code due to L57

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same comment as the automation-health-dashboard script.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same fix applied here in f7d006a — removed the unreachable -z guard, kept the .git check with the hint. (Conceding the same point as on the dashboard thread; my earlier "same comment" reply doesn't hold.)

Comment thread scripts/program-lib.sh Outdated
# standing orders) is version-controlled. Used to link report PRs back to the
# invoking program's standing order for auditability. Defaults to the
# automation repo under the active org; a fork can override to its own.
SOURCE_REPO="${SOURCE_REPO_FLAG:-${SOURCE_REPO:-${PROFILE_SOURCE_REPO:-$ORG/automation}}}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the SOURCE_REPO_FLAG doesn't seem to exist

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct — I added SOURCE_REPO with the full --flag > env > PROFILE_* > default idiom to mirror the other facts, but never wired a --source-repo flag into any arg loop, so the SOURCE_REPO_FLAG tier did nothing. Dropped it in f7d006a; SOURCE_REPO now resolves via env > profile > default, which fits it being a deploy-level constant rather than a per-invocation knob. Thanks.

Address evaline-ju review nits on rossoctl#47:

- link-health-scanner + dashboard: remove the unreachable
  '[ -z "$REPORT_TARGET_DIR" ]' guard. REPORT_TARGET_DIR falls back
  to $REPOS_DIR/$REPORT_TARGET_NAME, which always contains at least
  '/<name>', so it is never empty (an unset REPOS_DIR aborts earlier
  under set -u). Fold the actionable 'export MAIN_REPO_DIR' hint into
  the surviving .git existence check.
- program-lib: drop the SOURCE_REPO_FLAG tier from load_org_profile.
  No script parses a --source-repo flag, so the tier was inert.
  SOURCE_REPO is a deploy-level constant (env > profile > default),
  not a per-invocation knob.

Assisted-By: Claude Code (Anthropic AI) <noreply@anthropic.com>

Signed-off-by: Gloire Rubambiza <gloire@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human-review AI review passed, ready for human reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

decision: Fork naming after org rename refactor: Parameterize remaining kagenti couplings post-rename

4 participants