Skip to content

[C] #514 slice 9: Farm contract, with tenant identity staying in Platform #851

Description

@mforce

Important

Track C is unscheduled. These slices move production code, and the 2026-08 design's own status
line still governs: "proposed architecture; no production refactor is authorized by this
document."
Filed so the analysis is tracked work rather than a comment, not as a commitment to
run it.

The 2026-09-14 re-plan
recommends gating Track C on evidence from Tracks A and B: if the #842 ratchet fires repeatedly in
real pull requests, these become worth their cost; if it stays quiet, they do not. Track C is
57–95 focused engineering days and produces no user-visible change.

Read the re-plan before picking any of these up. Several assumptions in the 2026-08 plan are
corrected there.

Farm settings, logo, banner, currency, units and timezone behind a contract, while tenant identity
stays in Platform.

The one rule that must not bend

Tenant identity resolution stays claim-only in Platform. TenantResolutionMiddleware keeps populating
TenantContext directly from the JWT account_id claim, before any module contract runs. It must
not route through a Farm contract to establish tenant identity — that would either execute
tenant-filtered reads before TenantContext exists, or require bypassing the filters mid-request.
Either weakens the fail-closed tenant boundary (#530, #562, #673).

Farm contracts are called only after TenantContext is resolved, to read settings. Never to
resolve identity.

Scope

  • IFarmModule for settings, logo and banner; a small context reader returning an immutable
    currency/unit/timezone snapshot.
  • The lock-aware currency port the Finance pilot introduced becomes Farm's own.
  • Account and logo endpoints and the farm clock call the contract.

Carries a known cross-module edge

UpdateFarmSettingsHandler.cs:12 injects IEggUnitConversionRepository and :149 calls
DiscountCeiling.TryParsePercent (#727) — a real Farm → Commerce read the 2026-08 matrix marks —.
This slice decides whether it becomes a declared contract call or stays a declared edge. It is
legitimate either way; it must stop being accidental.

Done when

Explicitly not in this slice

TenantResolutionMiddleware, TenantContext, the stamp interceptor and middleware order — all
Platform, all unchanged.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiAPI/endpoint layerepic-514Modular monolith architecture (#514)priority:tier4Deferred or speculativesize:LSeveral days; wide blast radius or unresolved scopesliceThin vertical work itemtrack:C#514 Track C — moves production code; UNSCHEDULED, needs authorisation

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions