Skip to content

feat(engine): per-tenant configuration layer - #5804

Merged
JSONbored merged 1 commit into
JSONbored:mainfrom
lourincedaging0-commits:feat-tenant-config
Jul 14, 2026
Merged

feat(engine): per-tenant configuration layer#5804
JSONbored merged 1 commit into
JSONbored:mainfrom
lourincedaging0-commits:feat-tenant-config

Conversation

@lourincedaging0-commits

Copy link
Copy Markdown
Contributor

Closes #4787. Adds a pure, deterministic per-tenant configuration layer (packages/loopover-engine/src/tenant-config.ts) — a customer's own autonomy level (mirroring #4782's graduated dial, taken as a value) and repo-specific execution preferences, scoped strictly to their rented repo.

  • resolveTenantConfig(overrides) merges a tenant's overrides onto DEFAULT_TENANT_CONFIG, returning a config that shares no mutable reference with the defaults or any other resolution (the action-class list is copied every call); an unrecognized autonomy level falls back to the default rather than trusting arbitrary input.
  • setTenantConfig(store, tenantId, overrides) holds configs in an immutable store, returning a new store on every update and never mutating the input; getTenantConfig reads a tenant's effective config or the defaults.

Isolation (acceptance): guaranteed by construction — two tenants hold independent configs for the same loop mechanics, and setting or mutating one can never affect another's config or the shared defaults. Verified by a test that sets two tenants, mutates one's resolved list, and asserts the other tenant and the defaults are untouched.

Resolves and holds config only — persisting it to a datastore is a separate, maintainer-owned concern. Pure engine module, no IO. 100% statements/branches/functions/lines (verified locally: vitest coverage + engine build + tsc --noEmit clean on the changed files).

Adds a pure, deterministic per-tenant configuration layer for the Rent-a-Loop path (JSONbored#4787, part of JSONbored#4778):
a customer's own autonomy level (mirroring JSONbored#4782's graduated dial, taken as a value) and repo-specific
execution preferences, scoped strictly to their rented repo. resolveTenantConfig merges a tenant's overrides
onto the defaults, returning a config that shares no mutable reference with the defaults or any other
resolution; setTenantConfig holds configs in an immutable store, returning a new store on every update.
Isolation is guaranteed by construction, so one customer setting or mutating their config can never affect
another tenant's config or the shared defaults. An unrecognized autonomy level falls back to the default
rather than trusting arbitrary input. Resolves and holds config only; persistence is separate. Full coverage.

Closes JSONbored#4787
@superagent-security

Copy link
Copy Markdown
Contributor

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

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.11%. Comparing base (db74aa3) to head (fd3a58e).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5804   +/-   ##
=======================================
  Coverage   95.11%   95.11%           
=======================================
  Files         586      587    +1     
  Lines       46480    46494   +14     
  Branches    14860    14867    +7     
=======================================
+ Hits        44209    44223   +14     
  Misses       1515     1515           
  Partials      756      756           
Flag Coverage Δ
shard-1 43.73% <21.42%> (-0.01%) ⬇️
shard-2 36.23% <21.42%> (-0.01%) ⬇️
shard-3 32.14% <21.42%> (+0.06%) ⬆️
shard-4 32.74% <100.00%> (-0.09%) ⬇️
shard-5 31.63% <21.42%> (-0.01%) ⬇️
shard-6 44.52% <21.42%> (-0.01%) ⬇️

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

Files with missing lines Coverage Δ
packages/loopover-engine/src/tenant-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 gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 14, 2026
@loopover-orb

loopover-orb Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-14 20:01:26 UTC

3 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · unknown

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This adds a pure, isolated per-tenant configuration resolver and immutable store, plus barrel exports and tests. The mutable-reference-sharing concern is handled correctly (allowedActionClasses is spread into a new array on every resolve), the store update never mutates its input, and the autonomy-level fallback guards against arbitrary override values. Tests directly exercise the isolation guarantees described in the PR (mutating a resolved config doesn't leak into other tenants or the defaults), and CI is green across all checks.

Nits — 5 non-blocking
  • packages/loopover-engine/src/tenant-config.ts: maxConcurrentLoops and pauseOnFailure in preferences overrides aren't validated/clamped (e.g. a negative or non-finite maxConcurrentLoops would pass through), unlike the normalization pattern used in tenant-quota.ts's finiteNonNegativeInt — worth confirming this is intentionally left to a later consumer.
  • packages/loopover-engine/src/index.ts flagged as a long file (~618 lines) by the size check; this PR only adds 13 export lines to it, so the size issue predates this diff and isn't something this PR need fix.
  • test/unit/tenant-config.test.ts: no test exercises an overrides.preferences object that is itself undefined vs. omitted entirely — minor, since `prefs = overrides.preferences ?? {}` already covers both, but an explicit test would remove any ambiguity from the 100% coverage claim.
  • Consider whether maxConcurrentLoops/pauseOnFailure should be validated the same way tenant-quota.ts normalizes numeric inputs, since an untrusted override could otherwise set a negative or non-integer concurrency limit that downstream code may not expect.
  • If tenant IDs are ever attacker-influenced, note that setTenantConfig uses tenantId as a plain object key (Object.freeze({...store, [tenantId]: ...})) — worth confirming callers sanitize/validate tenantId before this layer, since keys like `__proto__` are handled safely by object spread but still worth a comment.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #4787
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low 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: 33 registered-repo PR(s), 12 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor lourincedaging0-commits; Gittensor profile; 33 PR(s), 0 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor — Code changes are accompanied by test evidence.
Review context
  • Author: lourincedaging0-commits
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 33 PR(s), 0 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
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.
[BETA] Chat with Gittensory

Ask Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @gittensory ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @gittensory chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @gittensory mention with a real question is routed to the closest matching read-only command automatically -- no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands

🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 14, 2026
@JSONbored
JSONbored merged commit 1fd8519 into JSONbored:main Jul 14, 2026
16 checks passed
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-tenant configuration layer

2 participants