Skip to content

feat(selfhost): add shared-base config layer for multi-repo operators (#1959) - #3660

Merged
JSONbored merged 1 commit into
mainfrom
claude/orb-phase1-1959
Jul 6, 2026
Merged

feat(selfhost): add shared-base config layer for multi-repo operators (#1959)#3660
JSONbored merged 1 commit into
mainfrom
claude/orb-phase1-1959

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Adds a third, lowest-priority manifest-loading layer to the existing container-private config
    directory (GITTENSORY_REPO_CONFIG_DIR): _shared/.gittensory.yml (.yaml/.json also
    accepted, same lookup order as every other candidate).
  • A self-host operator running many repos can now write one house review policy (e.g. a default
    review.tone, a baseline path_filters/wantedPaths set, common labeling_rules) once
    instead of copy-pasting it into every repo's per-repo file or the global default.
  • Precedence: per-repo file overlays the global default, which now overlays the shared base
    (shared base → global → per-repo, ascending priority). This reuses the exact same
    mergeConfigOverlay deep-merge/array-replace/explicit-null-clear helper the existing
    per-repo/global layers already use — no new merge algorithm. mergeConfigOverlay itself is
    untouched.
  • combineConfigText (binary, 2-layer) is generalized into combineConfigLayers (N-way fold over
    an ascending-priority list), preserving every existing fallback rule: 1 layer present → its raw
    text unchanged; 2+ parse → deep-merged JSON; 0 parse → highest-priority present layer's raw text.
    A malformed/oversized/non-mapping layer is dropped from the fold and never blocks a review.
  • No new schema field: review.shared_config from the issue title describes the loading
    pipeline
    change, not a new key under FocusManifestReviewConfigfocus-manifest.ts and
    focus-manifest-loader.ts are unchanged. Confirmed via the .gittensory.yml.example
    field-exhaustiveness test (test/unit/focus-manifest.test.ts), which needed no new entries and
    passes unchanged (442 tests).
  • Absent shared base (the default, common case) is byte-identical to the pre-feat(review): review.shared_config — operator-level base manifest overlay #1959 2-layer
    behavior — verified by re-running every pre-existing private-config.test.ts case unchanged
    (all 39 pass with zero edits).
  • Docs: new "Shared base layer (multi-repo operators, feat(review): review.shared_config — operator-level base manifest overlay #1959)" section in
    config/examples/README.md, updated directory-layout block and precedence chain (now 6 layers),
    updated overlay-semantics prose for N-way folding, and a new worked example (shared + global +
    per-repo, all three present). Added config/examples/shared.gittensory.yml as a copy-paste
    starter, mirroring the existing global.gittensory.yml/repo-override.gittensory.yml pattern.
    Small descriptive comment update in docker-compose.yml near the existing
    GITTENSORY_REPO_CONFIG_DIR env var comment.
  • Known, deliberately-accepted limitation documented in the module header: a repo literally named
    _shared would collide with the shared-base folder name (repo segments allow _ as an interior
    character). No functional fix; documented as an operator-side naming convention instead.

Closes #1959

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked an issue, or this is small enough that the summary explains why an issue is not needed.

Validation

  • git diff --check
  • npm run actionlint — not run locally; no workflow/YAML files touched by this PR, CI will confirm.
  • npm run typecheck — clean.
  • npm run test:coverage locally; codecov/patch requires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate. — ran the affected suite directly (test/unit/private-config.test.ts, test/unit/selfhost-config-examples.test.ts, test/unit/focus-manifest-loader.test.ts, test/unit/focus-manifest.test.ts; 530 tests) with --coverage --coverage.reporter=json, then cross-referenced every changed line range in src/selfhost/private-config.ts (from git diff origin/main --unified=0) against coverage-final.json's statementMap/branchMap/fnMap in a small script: zero uncovered statements, branches, or functions in any changed range. The whole file reports 100% statements/branches/functions/lines. Did not run the full unsharded npm run test:coverage across the whole repo, per this repo's own guidance to avoid duplicating the CI gate locally for a narrowly-scoped change — CI will run it in full.
  • npm run test:workers — not run locally; this PR touches no Workers-runtime code path (Node-only src/selfhost/**), CI will confirm.
  • npm run build:mcp — not run locally; no MCP package changes in this PR.
  • npm run test:mcp-pack — not run locally; no MCP package changes in this PR.
  • npm run ui:openapi:check — not applicable; no API/OpenAPI schema changes. Also ran npm run cf-typegen:check and npm run db:migrations:check proactively (both clean) even though neither wrangler bindings nor the DB schema changed.
  • npm run ui:lint — not run locally; no apps/gittensory-ui/** changes in this PR.
  • npm run ui:typecheck — not run locally; no apps/gittensory-ui/** changes in this PR.
  • npm run ui:build — not run locally; no apps/gittensory-ui/** changes in this PR.
  • npm audit --audit-level=moderate — not run locally; no dependency changes in this PR (no package.json/lockfile edits).
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries — see the new describe("makeLocalManifestReader — shared base layer (#1959)", ...) block: shared-only, repo-only (byte-identical regression case), shared+repo (no global), all-three-present (fold-direction correctness), array-replace-wholesale across 3 layers, explicit-null-clear across 3 layers, malformed shared file with repo+global present (fail-safe, non-blocking), oversized shared file as the only other layer (fail-safe, non-blocking), all-three-malformed fallback, and exact candidate-path ordering (.yml.yaml.json).

Also ran (not in the template's list, but relevant to this change): npm run selfhost:env-reference:check (clean — no env.SOMETHING reads added/moved) and node scripts/check-docs-drift.mjs (clean).

If any required check was skipped, explain why:

  • The UI/MCP/Workers/audit checks above were skipped because this PR's diff is entirely
    src/selfhost/private-config.ts + tests + docs + one docker-compose.yml comment line — none of
    those surfaces are touched. CI's test:ci runs the complete gate regardless; I ran the narrower,
    directly-relevant local checks (typecheck, the affected test files with coverage
    cross-referenced line-by-line, migrations/cf-typegen/env-reference/docs-drift checks) rather than
    duplicating the whole suite locally for a change this scoped.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. — not applicable; no auth/cookie/CORS/session code touched.
  • API/OpenAPI/MCP behavior is updated and tested where needed. — not applicable; no API/OpenAPI/MCP surface touched.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. — not applicable; no UI changes.
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. — not applicable; no visible UI change (backend/docs only).
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. — config/examples/README.md updated; CHANGELOG.md intentionally untouched.

Notes

  • This is purely a manifest-loading-pipeline change, not a new field on the parsed manifest
    schema — src/signals/focus-manifest.ts and src/signals/focus-manifest-loader.ts are
    unchanged, and test/unit/focus-manifest.test.ts's .gittensory.yml.example
    field-exhaustiveness maps needed no new entries (verified by running that file's full 442-test
    suite unchanged).
  • Deliberately left out of scope, per the issue's own "Effort: M" framing and to keep the diff
    narrow: no changes to focus-manifest.ts/focus-manifest-loader.ts (none needed — the loader
    already treats the private-config reader's return value as an opaque already-merged string), no
    new env var (the issue explicitly asks to build on the existing GITTENSORY_REPO_CONFIG_DIR,
    which this does).
  • Known, deliberately-accepted limitation (documented in the private-config.ts module header): a
    repo literally named _shared would be shadowed by the new shared-base folder name, since
    isSafeRepoSegment permits _ as an interior character in a repo segment. Flagging here per the
    brief's request — no functional fix proposed; an operator hosting such a repo should use a
    private, documented workaround rather than relying on automatic disambiguation.

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 6, 2026
@loopover-orb

loopover-orb Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-06 02:04:04 UTC

6 files · 1 AI reviewer · no blockers · readiness 82/100 · CI green · clean

⏸️ Suggested Action - Manual Review

  • Touches a guarded path — held for manual review: This PR changes guardrail-protected path(s): src/selfhost/private-config.ts (matched src/selfhost/**).

Review summary
This generalizes the existing 2-layer per-repo/global config merge into an N-way ascending-priority fold (shared base → global → per-repo) via a new combineConfigLayers, replacing combineConfigText, while reusing the untouched mergeConfigOverlay deep-merge helper. The fold order, fallback rules (single-layer raw passthrough, all-unparsed → highest-priority-present raw text, dropped malformed/oversized layers), and Promise.all read order all correctly match the documented semantics and the pre-existing single/dual-layer behavior is preserved byte-for-byte when no shared base is mounted. Test coverage is thorough (12+ new cases covering fallback, 3-way merge, array replace-wholesale, null-clear, malformed/oversized-layer drop-out, extension precedence, and invalid-repo-name short-circuit) and docs/examples/docker-compose comments are updated consistently.

Nits — 7 non-blocking
  • src/selfhost/private-config.ts: the shared-base path `_shared/.gittensory.yml` can collide with a real per-repo bare-folder path for a repo literally named `_shared` (owner/_shared); this is explicitly documented as an accepted edge case in the header comment, but consider a less collision-prone folder name (e.g. `__shared__`) to remove the ambiguity entirely rather than relying on an operator convention.
  • The external analysis flags the literal `3`/`1959` in `combineConfigLayers`/comments as 'magic numbers' — these are just an array-length check and an issue reference in a comment, not meaningful constants worth extracting.
  • config/examples/README.md's new Example 4 section is fairly long; consider trimming given three other precedence examples already exist, though this is purely a style call.
  • Consider adding a short JSDoc note on `combineConfigLayers` (already present) cross-linking to `SHARED_BASE_CONFIG_CANDIDATES` for discoverability — currently only inferable by reading `makeLocalManifestReader`.
  • If operators are likely to run many repos, consider validating at startup (or documenting) that no configured repo is literally named `_shared` to avoid the folder collision silently double-counting the same file as two layers.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
  • Touches a guarded path — held for manual review — A maintainer must review and merge this change.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #1959
Related work ⚠️ 3 scoped overlaps Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 55 registered-repo PR(s), 46 merged, 457 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 55 PR(s), 457 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: Python, TypeScript, JavaScript, Ruby, Go, Kotlin, MDX, Shell
  • Official Gittensor activity: 55 PR(s), 457 issue(s).
  • Related work: Titles/paths share 10 meaningful terms. (issue #2046, issue #1959)
  • Related work: Titles/paths share 8 meaningful terms. (issue #2189, issue #2184)
  • Related work: Titles/paths share 7 meaningful terms. (issue #2049, issue #2046)
  • Additional title-only matches omitted; title-only overlap does not block.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Review top overlaps.
  • Add a concise scope and risk note.
  • No action.
  • Check active issues and PRs before submitting.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.29%. Comparing base (2156f42) to head (244bf35).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3660   +/-   ##
=======================================
  Coverage   93.29%   93.29%           
=======================================
  Files         314      314           
  Lines       32057    32061    +4     
  Branches    11748    11747    -1     
=======================================
+ Hits        29906    29910    +4     
  Misses       1517     1517           
  Partials      634      634           
Files with missing lines Coverage Δ
src/selfhost/private-config.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 6, 2026
…#1959)

Adds a third, lowest-priority manifest-loading layer inside the existing
GITTENSORY_REPO_CONFIG_DIR: `_shared/.gittensory.yml`. A self-host operator
running many repos can now write one house review policy (tone, path
filters, labeling rules) once instead of copy-pasting it into every repo's
private config. The repo file still overlays the global default, which now
overlays the shared base, using the same deep-merge/array-replace/explicit-
null-clear semantics the existing per-repo/global layers already use.

No shared file mounted (the default case) is byte-identical to prior
behavior; a malformed/unreadable shared file is dropped from the merge and
never blocks a review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Development

Successfully merging this pull request may close these issues.

feat(review): review.shared_config — operator-level base manifest overlay

1 participant