Organization Core — contract inventory (ST-931)

Where identity, authorized scope, selected scope, target, freshness, enforcement and outcome actually live in propflowai today — per entry-point family, with the existing test that exercises each and the board row that owns each gap.

Inspected commit 94172a0fad7ba2170f60345521455d98ffcd2d4c (propflowai origin/main, 2026-09-16 16:37:56 −0500) · board read at propflow-docs f4e676628c9489f750f631de51f886275d9c73c9 · deliverable of board row p10-core-contract · this is an inventory, not a completion receipt

The contract exists as code. It is not the contract most entry points go through. Every responsibility PC1 names has a real, well-documented implementation in this repo — and three of the seven have a second, live implementation as well, in one case with three times the importers. The scope machinery that reaches durable work is built and largely dark: exactly one of 36 workflows pins and re-checks its scope, behind a patched() flag, and its only enforcing verdict is armed on two bench buildings. The 40 scheduled HTTP jobs take no scope argument at all.

How to read this page

Every implementation claim below names a file and a line at the inspected sha. Claims are labelled by how they were established:

Counts from git grep are ceilings, not measurements of behaviour: a grep proves absence only of the spelling searched, and presence only of a string. Every zero reported on this page was run in the same command as a spelling known to be present, so that a zero caused by a bad path or a shell-glob failure would have shown up as a zero on the control too. Where that control is not stated, treat the zero as unverified.

1 · The PC1 envelope already exists as a type

PC1 asks for a logical envelope carrying verified actor or workflow identity, authorized scope, this request's selected scope, canonical target ids, coverage, the relevant revision basis, and for writes an operation identity and explicit outcome. No new universal context type is needed. TenantContext already carries all but two of those, and four sibling context types exist beside it.

PC1 responsibilityField on the existing typeWhere
verified actor / workflow identityactor?: ActorView (personId, tier, projection, buildings, actingOrg) and job?: JobRef (runId, reason)src/lib/domain/portfolio/context/mint.ts:181, :224
authorized org / property scopeorganizationId, propertyId, roster, reachmint.ts:200:220
this request's selected scopeabsent from the context. Lives separately in Selectionsrc/lib/domain/scope/selection.ts:267
canonical target / resource idspath: ScopePathView, address?mint.ts:94
revision / freshness basismapVersion: numbermint.ts:220; read at MintSource.mapVersion :500 = ORG#<org>/PROFILE.mapVersion
boundary enforcementcheckPartition(ctx, pk); WALLED_PREFIXES = ['PROP','ORG','GROUP']src/lib/domain/portfolio/context/wall.ts:74, :65
write operation identity + explicit outcomeabsent from the context. Exists per-lane (see §6)

The five minted context kinds are TenantContext :200, AdminContext :232, ComplianceContext :241, LifeSafetyContext :251, and the reports context. Their non-test caller census at this sha:

MinterNon-test caller files
mintFromAddresssrc/lib/temporal/activities/collections-scope.ts
mintFromSessionportfolio/actor-measure/delta.ts · portfolio/context/session-view.ts · scope/addressed-write.ts
mintFromSnapshotdata/dynamo/proporg-roster.ts · context/dynamo-snapshot-source.ts · temporal/activities/collections-scope.ts · temporal/workflows/collections-chase-workflow.ts
mintFromConversationdata/dynamo/voice-call-scope.ts · domain/voice/pin-call-scope.ts
mintForJobdomain/vendors/vendor-engagement.ts
mintAdminsrc/app/api/vendors/route.ts · domain/bench/personas.ts · context/session-view.ts · scope/org-level-guard.ts · domain/vendors/load-vendors-list.ts
mintLifeSafety (:861) · mintReports (:874)none — defined, zero non-test callers each
mintCompliancedoes not exist. ComplianceContext (:241) has no minter; it is produced only by the one-way narrowing forCompliance(ctx: TenantContext) at :850, which itself has zero non-test callers

Controls for those zeros, run in the same commands: mintFooBar → 0 while the six rows above returned non-empty; mintAdmin → 5 files under the identical exclusion filter that gave mintLifeSafety/mintReports zero. The minters are exactly eightmintFromAddress :528, mintFromSession :592, mintFromSnapshot :663, mintFromConversation :731, mintForJob :790, mintAdmin :833, mintLifeSafety :861, mintReports :874. Files importing portfolio/context/mint at all (non-test): 6. Exactly one route handler touches the context machinery, and through mintAdmin.

2 · One authoritative source per responsibility — and the three that have two

ResponsibilityAuthoritative implementationImporters
(non-test / total)
Second live implementation
Effective scope (authorized ∩ selected)scope/selection.ts:404 deriveSelection — "the only constructor of a Selection"; request seams scope/read-scope.ts:184 readScope and scope/get-selection.ts:85 mintSelection, both calling the same resolveGrantsFor + chooseProposal + deriveSelection. The seam most routes actually reach is a third one: dashboard/scope/route-scope.ts:168 readDashboardScope / :195 dashboardScopeOf / :248 computeScopeOf, named in 31 files under src/app — against 4 for readScope16 / 34yes platform/auth/scope.ts:96 getUserPropertyScope reads the stored User.assignedPropertyIds; the intersection is then open-coded per route with org-scope.ts:248 intersectScopes45 calls across 32 files, 10 of them the three-way nested fold, e.g. src/app/api/leasing/renewals/route.ts:144
Memberships & grantsdata/dynamo/org-membership.ts:194 recordOrgMembership; property grants via scope/grants.ts:123 grantsFromRoleRows over PersonRole rows9 / 27 · 3 / 9no — but the org-membership rows are written and not read (the module's own header); resolvePersonHomeOrg is still the runtime answer
Settings registry + resolverportfolio/registry/keys.ts:67 KEYS (61 keys, founder-ratified 2026-09-14) + portfolio/scope/resolve-effective.ts:260 foldEffective / :532 resolveEffective41 / 56 · 10 / 13yes src/lib/platform/settings-resolver.ts:88 resolveSettings — its own inheritance walk with its own DEFAULTS :36, zero references to resolveEffective or the registry, yet its header cites a key that IS registered (keys.ts:132). 29 / 80 importers — roughly three times the canonical resolver.
Scoped repositoriesportfolio/context/repository.ts getRepository(ctx) + context/wall.ts:74 checkPartition0 / 0 — darkeffectively — the reads happen through data/dynamo/helpers.ts:1643 queryByPK and siblings, 191 non-test call sites of queryByPK( alone, none through the wall
Reservationsdata/dynamo/calendar-slot-reservation.ts:391 holdSlot (+ submitSlot :521, bookSlot :537, releaseSlot :564); states 'held' | 'submitted' | 'booked' :1615 / 7noleasing/tour/slot-hold.ts wraps it; exactly one caller of holdSlot( outside its definition; wiring drift-pinned by calendar-slot-reservation-wiring.drift.test.ts
Durable effect / workflowsrc/lib/temporal/ — 36 workflows, barrel workflows/index.ts:18-53; idempotency mint temporal/saga-mint.tspartial — the SQS work-order-create path (ADR-0030) is a second durable-effect mechanism; agents/clara/lib/messaging/inbound-dispatcher.ts:405 is the only code site that spells "durable effect"
Platform Admin boundarynot found as specified Today: platform/auth/helpers.ts:730 isActivePlatformAdmin (a role predicate, 76 references)76 refsyes, twice over platform/auth/staff-domain-override.ts:72 grants platform_admin from an email domain suffix, consumed at helpers.ts:312-313 and :377 (staffOverrideApplied ? 'platform_admin' : …) and src/app/api/auth/me/route.ts:244. The suffix rule itself has three spellings: identity/internal-address.ts:54, components/primitives/nav-items.tsx:599, and a raw literal at agents/clara/lib/email/auto-reply-guard.ts:286

3 · The grid — entry-point family × chain stage

Each cell names where the stage is decided, or says it is not decided. +/− means a positive and a negative control exist for that stage in that family; + only means no negative control was found; none means neither.

Good where the org is re-derived from the record (tools.ts:1078, :1144, tools-leasing.ts:1087-1090, _turnover-shared.ts:254-257). Four Ask Clara readers check a proposed id against the authorized set — a legitimate shape — with the property axis only; one (:1477) checks nothing. See §4C. + only Two kinds. Duplication: renewal-receipts.ts:279, outreach-send-claim.ts:111, pending-notices.ts:305/:372. Scope: checkpointCollectionsScopeActivity (collections-scope.ts:130) re-mints via mintFromSnapshot before each notice and returns ok / refused{reason, enforce} / unavailable. Only scope_moved is ever enforced, and only when rosterGateModeFor(propertyId) === 'refuse' — the same two bench buildings. Every other verdict is recorded and the cadence continues. +/−
StageA · User APIs (462)B · List/detail reads (155 pages)C · Internal tools / AI (151+52+23)D · Background sync (94)E · Durable workflows (36)
Verified principal / workflow identity auth/helpers.ts:801 requireUser, :739 requireAdmin, :147 enrichAuthenticatedUser. 230 of 462 routes name an enforcing require*; 94 use getCurrentUserUnchecked (:649), which returns null rather than refusing. +/− auth/request-user.ts:15 getRequestUser via mintSelection (get-selection.ts:85); older pages take headers() and call getCurrentUserUnchecked inside the loader. +/− Ask Clara: ToolContext.user (dashboard/chat/tools.ts:415). Clara conversational: the runtime-supplied conversationId, never the model. Operator run route: authorizeAdminOrBearer. +/− none. requireCronOrAdminAuth (platform/security/admin-auth.ts:41) compares a bearer secret at :64-67 and carries no principal. Lambdas take no principal at all. none No human principal enters a workflow — correct by design (ALIGN2: a tab must not retarget a workflow). What a run carries instead is a pinned scope, in one of 36: pinCollectionsScopeActivity (activities/collections-scope.ts:91). + only
Authorized scope Three legs: property auth/scope.ts:96, org auth/org-scope.ts:36, roster require-in-roster.ts:427. 281/462 routes import the trio. +/− scope/grants.ts:215 resolveGrants from PersonRole rows (new path) vs getUserPropertyScope off the stored list (old path). +/− Per-handler, six different spellings: isPropertyInOrgScope, canViewProperty, isInScope, scopeByOrg, assertWorkOrderActorAuthorized, isTurnoverInPmOrgScope. No single choke point a new tool inherits. +/− none. git grep -l "domain/scope" -- src/app/api/cron/**0; the same call's control requireCronOrAdminAuth38. none Built, and dark in 35 of 36. collections-chase-workflow.ts:262 pins {organizationId, propertyId, mapVersion} behind patched('collections_scope_pin_v1') and re-checks it at :320. The other 35 carry entity ids only and their activities re-derive org from the row they load. An absent organizationId in a workflow's initial input is not evidence that the run is unscoped. +/−
Selected scope selection.ts:404 deriveSelection from read-scope.ts:97 requestProposal; cookie may fill in only where the address said nothing (chooseProposal :602). +/− get-selection.ts:85 mintSelection — zero-arg and react.cached so no component can ask a different question; fails closed via refusal() :48. Used by ~2 of ~15 list pages. +/− n/a by design — ALIGN2 says a tool is not a viewer's tab. In practice the Ask Clara ToolContext.scope IS the viewer's selection, so tools inherit it. + only n/a by design, and correct: a tab must not retarget a sync. n/a n/a by design. n/a
Canonical target / resource scope/addressed-write.ts:168 addressOfRow, :258 authorizeAddressedWrite — the write takes its org from the row, not the picker. One production caller: src/app/api/vendors/route.ts:183. +/− Detail loaders re-derive: properties/load-property-detail.ts:43-49 canCallerViewProperty; collections via leasing/collections/resolve-account.ts:63 (404-not-403). +/− Derived from the row where a row exists (inbound-processor/handler.ts:722,729); otherwise the whole estate. none Entity id is the only target; activities load the row and re-derive. + only
Revision / freshness basis No authorization version anywhere. grantVersion/authVersion/membershipVersion → 0/0/0 (control SCOPE_KEY_VERSION → 33). none scopeKey (selection.ts:637) = sel2: + resolved ids. Scope is in the key; no auth version, no principal. Detail caches carry neither (propflow:tenant:<id>, TenantDetailClient.tsx:213). none None. Tools read live rows per call. none None. none mapVersion is pinned at workflow start for the one workflow that mints a context; SnapshotView (mint.ts:161) carries {organizationId, propertyId, mapVersion} and its comment reads "What a workflow pinned at start (§4.6)". + only
Boundary enforcement Property + org legs live; roster leg dark by defaultrosterGateModeFor :307 returns off unless PROPFLOW_ROSTER_GATE is set or the building is in config/roster-refuse-properties.json (2 bench buildings). requireInRoster is imported by 0 route files; it reaches 16 routes via helpers.ts:1012 → :1063. +/− read-over-scope.ts:98 readOverScope — 17 non-test callers, 13 of them routes. Older list pages instead read wide and filter in memory (load-properties-list.ts:55-64). + only for the old path Per-handler. toolFence/scopedTool/assertToolScope → 0 each; orgLeg → 14, all in test files. +/− for three tools, none for five A shared bearer secret. Nothing else. none
Outcome HTTP status. ALIGN1: a 200 is not an authorization decision. + only Rows or an empty list. +/− A tool result object; refusals are {error} strings or refused: true. +/− Handler return value; no receipt contract. none Six per-domain unions, no shared enumrenewal-workflow.ts:83 DeliveryStatus, :85-93 PMSState (incl. unknown), data/types.ts:5280 VoiceChannelOutcome, pending-notices.ts:86, outreach-send-claim.ts:85, voice/provider/contract.ts:200-217 AdapterErrorCode (incl. uncertain). +/−

4 · Per family — entry points, harness, controls, owning row

A · User APIs — 462 route handlers

B · List/detail reads — 155 page.tsx, 114 server-rendered

C · Internal tools / AI — three registries, not one

RegistryWhereCountWhat it is
TOOL_CATALOGsrc/lib/tools/index.ts:37151Operator catalog; exhaustiveness compile-enforced against the ToolKey union (tools/types.ts:438)
handleToolCallagents/clara/lib/agent/tools/index.ts:17752The single tool_use → handler boundary for SMS / email / voice; 24-case switch at :256-344, 87 handler files
dashboardChatToolsdomain/dashboard/chat/tools.ts:110, dispatch :55423"Ask Clara", read-only, its own ToolContext
ToolWhat the check actually isWhat the read is bounded byResidual concern
:1353 listMaintenanceManuals
:1373 listFinancialPeriods
isInScope(propertyId, ctx.scope) against the authorized set, before the readthe same id: getFinancialPeriods filters p.propertyId === propertyId (store.ts:5134); manuals likewiseUNVERIFIED property axis only, no org leg. Matters only if a property id can be reachable across orgs — not established here
:1363 getTenantBalanceHistoryisInScope(propertyId, ctx.scope) before the readthe authorized property is the partition key: PK=PROP#{propertyId} SK=BAL#{tenantId}# (dynamo/property.ts:1602-1607); the JSON twin filters on both fields (store.ts:3698). A foreign tenantId reads nothing outside the checked buildingno escape found the earlier "the tenant record's own property is never consulted" was misleading — it does not need to be
:1345 listAppliancesconst propertyId = unitId.split('-')[0] — the first hyphen — then isInScopethe data layer derives the last hyphen instead: unitId.substring(0, unitId.lastIndexOf('-')) (dynamo/property.ts:1426), and unit ids are `${propertyId}-${unitNumber}` by construction (data/types.ts:116)UNVERIFIED the two derivations disagree whenever a property id itself contains a hyphen. In the general case the tool's id is narrower, so it fails closed; a cross-property read needs a property id that is a hyphen-prefixed prefix of another and is held by the caller. Whether such a pair exists is not established here
:1477 appfolioReportnone. if (typeof input.property_id === 'number') params.property_id = input.property_id; reaches the PMS unchecked, and the returned rows are not filtered afterwards — client.listAll(endpoint, params) is returned through truncateNoteonly the credential. resolveAppfolioClientForScope (integrations/appfolio/resolve-client.ts:24) collects the unique ownerIds from the already-scoped ctx.properties, appends fallbackUserId (the requesting user, "admins sometimes store creds under their own account for testing", :6-8), races them and takes the first that constructsUNVERIFIED, and the sharpest of the five The right comparison is the provider-returned property population against the caller's authorized operation scope — not against the org. A per-org credential would not settle this: a caller who holds only property A inside an org that also owns B still requires B to be unreachable, and an AppFolio account credential's reach is the account's portfolio, which is not bounded by the caller's property set. Add that the credential is chosen by whichever owner resolves first, so the account that answers need not be the owner of the property the caller named. Stays UNVERIFIED until a test grants A, forbids B, drives the real dispatch, and asserts on both the query issued and the rows returned

One cross-cutting fact behind all four: isInScope returns true unconditionally when scope === null (auth/scope.ts:148-152), and getUserPropertyScope returns null only for platform_admin (:96-101). That is the documented Admin exception, not a leak — and it is exactly why ToolContext's own docblock insists the user field is required: "scope alone is the PROPERTY axis and cannot answer the org question".

D · Background sync — 94 entry points

E · Durable workflows — 36 production workflows

5 · Business records vs minimal authorization metadata

The row asks for this distinction explicitly, because ALIGN2 turns on it: reading the metadata is not permission to read the rows.

Authorization metadata (may be read to establish the set)Where
PersonRole rows — the grantdata/store.ts:6531 getPersonRoles, :6545 getPersonRolesAcrossOrgs; consumed by scope/grants.ts:123
The organizationId stamp on a Property rowused by org-scope.ts:226 isPropertyInOrgScope and by every tool that re-derives org from a record
The roster indexdynamo/property.ts:213 getPropertiesViaRoster via GSI_PROPORG
Org membership rows (written, not yet read)data/dynamo/org-membership.ts
The legacy stored list User.assignedPropertyIdsdata/types.ts; read by auth/scope.ts:96 in 135 non-test files
Settings registry keys and their locksportfolio/registry/keys.ts:67 (61 keys)

Everything else — work orders, conversations, tenants, leases, prospects, tours, renewals, turnovers, vendors, appliances, financial periods, balance history — is a business record, and ALIGN2's intersection must be computed before the query that returns it, not applied to its result.

6 · ST-931 – ST-939 mapped to existing tests

ControlOwning rowExisting test(s) it maps toVerdict
ST-931 · contract inventoryp10-core-contract (implied only)this page; scripts/check-raw-store-importers.ts executed as its one instrumentinventory, not a proof
ST-932 · scopep10-core-scopescope/__tests__/read-over-scope.test.ts · selection-never-wider-than-grants.test.ts (13 cases) · write-addressed-by-the-row.test.ts · vendors/__tests__/vendors-read-the-set.test.ts:240 · work-orders/__tests__/cross-org-derived-work-order-and-chat-ids.test.ts · src/__tests__/scope.test.tscovered at unit level — what is missing is the per-route trace of what each caller passes
ST-933 · freshness / revocationp10-core-freshnessThe nearest existing control is the durable one: src/__tests__/collections-scope-activity.test.ts exercises a real re-resolve against a pinned mapVersion and the recorded-vs-enforced split (:72 map moved 3→4 → ok at the live 4; :81/:89 scope_moved recorded then enforced). On the request path: no test revokes a grant, acknowledges the write and repeats a protected read. Revocation is honoured by the r.active predicate (grants.ts:216); whether any test exercises that filter should be checked in grants-resolved-per-org.test.tspartial — a version re-resolve exists in one workflow; no revocation race control anywhere
ST-934 · resources / capacityp10-core-resourcessrc/__tests__/calendar-slot-reservation-wiring.drift.test.ts (wiring pin, not contention); scripts/report-stuck-slot-reservations.tspartial — no contention test found
ST-935 · outcomes / retryp10-core-outcomesrenewal-workflow-retry-letter-guard.test.ts:297 · renewal-send-guard.test.ts:63 · renewal-receipts.test.ts:124, :153 · renewal-sms-real-dispatch-suppression.test.ts:332, :351 · the 7 replay-corpus suitesstrongest existing coverage
ST-936 · source identity / metricsp10-core-datalambda/appfolio-sync/__tests__/onboarding-import-runner.test.ts:1615 (a count regression, not an isolation control)gap
ST-937 · Atlas & Settings surfacesp10-core-surfacesplatform/auth/__tests__/is-active-platform-admin.test.ts · admin-emails-is-not-a-provisioner.drift.test.ts · domain/settings/settings-levels.ts:29 pins the four sectionspartial — nothing tests the domain-suffix grant's effect
ST-938 · replayp10-core-replayscripts/portfolio-harness/ (28 registered cases) · 7 replay-corpus suites · evals/replay-harness/ (conversations, not Temporal)harness exists
ST-939undefined on the boardambiguity for the driver

Where ST-931 should be registered — and the problem with that instruction

The row says to record the inventory "in this row's dropdown and existing harness registry". Two candidates exist and neither fits cleanly:

7 · Gaps, each routed to an owning row

None of these is a claim that something is broken in production. Each is a path that is unimplemented or unproven, stated as a gap rather than glossed.

#GapEvidence at the inspected shaOwning row
G1Two authorized-set definitions live inside one request; the intersection is open-coded per route rather than behind the facadescope/grants.ts:215 vs auth/scope.ts:96; intersectScopes at 45 call sites in 32 files; the divergence is documented in the code itself at dashboard/scope/route-scope.ts:19-27 — an impersonating platform admin is fleet-wide on the unproposed path and narrowed on the proposed onep7-actor-view, ui-s-d
G2A second settings resolver with its own inheritance walk, three times as widely imported as the canonical oneplatform/settings-resolver.ts:88, 29/80 importers, zero references to resolveEffectivep3-registry-drift / Phase 3 settings rows
G3Platform admin is still granted by email domain suffix; no enumerable three-identity roster existsauth/helpers.ts:377; suffix rule spelled three ways; roster search returned 2 test commentsp7-domain-override
G4The cache key carries the effective scope but no authorization version; a tier demotion over an unchanged property set yields a byte-identical keyselection.ts:637 scopeKey; grantVersion/authVersion/membershipVersion all 0 against a control of 33p10-core-freshness, ui-s-a
G5Detail-page caches are keyed on entity id alone — no scope, no auth versionTenantDetailClient.tsx:213, PropertyDetailClient.tsx:397, ProspectDetailClient.tsx:1324, VendorDetailClient.tsx:85; VendorsClient.tsx:192 spells a key inline against selection.ts:645-650's own ruleui-s-d
G6Both authorization legs are eventually consistent — one by omission, one by GSI constructionperson-roles.ts:134-140 omits consistentRead; dynamo/property.ts:168/:213 are GSI queries; queryGSI has no consistency parameterp10-core-freshness
G7Fail-open in a list loader: a null viewer receives every tenant in the deploymentdomain/tenants/load-tenants-list.ts:36user ? scopeByProperty(tenants, getUserPropertyScope(user)) : tenants. auth/scope.ts:19-21 documents the opposite contract. Not reachable today: src/middleware.ts covers /api/* and /api/tenants is not in the public allowlist — so this is defence-in-depth, not a live unauthenticated readui-s-d or p1-roster-refuse — driver to route
G8UNVERIFIED appfolio_report passes a model-supplied property_id to the PMS with no PropFlow-side check and no filter on the rows returned. The test is the provider-returned property population against the caller's authorized operation scope — a per-org credential does not settle it, because a caller holding only property A in an org that also owns B still requires B to be unreachable. The other four proposed-id readers check against the authorized set and are bounded by the checked id (§4C); their residual is the missing org axis, also UNVERIFIEDdashboard/chat/tools.ts:1477 (unchecked); credential chosen by first-owner-to-resolve, with a fallback to the requesting user, at integrations/appfolio/resolve-client.ts:24-38; :1345, :1353, :1363, :1373 (checked, property axis only). Needs an A-authorized / B-forbidden control driving the real dispatch and asserting on the query AND the result before any of these is called a defectp8-pickvendor-* / Phase 8 tool-fence rows
G8bAsk Clara applies authorized scope only — no selected-scope leg on a viewer-initiated readsrc/app/api/dashboard/chat/route.ts returns 0 for every selection spelling, against a control of three sibling dashboard routes that use readDashboardScope. Fail-safe in direction (selection cannot widen), but not ALIGN2's intersection. Not to be copied into families D or E, which use their own authorized operation scopeui-s-d · p10-core-scope
G9The cross-org census guard's regex cannot see the four proposed-id readers — a coverage gap in the guard, not a verdict on the readerscross-org-derived-work-order-and-chat-ids.test.ts:581; the suite is green at 28/28 while they sit outside its censusp10-core-scope (ST-932)
G10No route-layer scope argument on any scheduled HTTP job, and no scope helper imported by one. That is a statement about arguments and imports, not about downstream scoping, which is unproven in either direction38 cron routes with 0 domain/scope references against a control of 38 in the same command; six no-arg lambdas. Not claimed: that no mechanism exists — the durable lane shows the repo spells this SnapshotView/mintFromSnapshot. Before anyone prescribes an implementation, the actual connection/operation scope each job already runs under has to be traced — dispatch → activity → authoritative read/effect, per family. That is ST-932/ST-933 work, not this row's, and not a licence to add a scope argument to 38 routesrouting question — see below
G11No isolation control in the cron, lambda, Fargate or scheduled-CI families (the durable-workflow family does have one). Same distinction as G10: an absent control is not a demonstrated leak — it means nobody has driven an A-authorized / B-forbidden case through these paths274 cross-org test files, exactly one under lambda/ and it asserts a countsame routing question
G12The workflow scope pin exists in 1 of 36 and is dark: only scope_moved enforces, and only under the roster gate's refuse mode. No test revokes a grant and asserts the next effect is refusedcollections-chase-workflow.ts:262/:320; collections-scope.ts:174-175; control executed at collections-scope-activity.test.ts:81/:89 → 10/10p9-workflow-pins (the pin itself); p1-roster-refuse (the gate arming); p10-core-freshness (the revocation proof)
G13The scoped repository has no runtime importer and the reads bypass the wall; two of the eight minters and the compliance narrowing have no callercontext/repository.ts has 0 runtime importers — its only two references are import type { ScopedRepository } at relationships/read-relationships.ts:65 and reports/push-report.ts:88 (control: context/wall → 10 files). queryByPK( outside helpers.ts itself: 212 occurrences across 84 non-test files, none through the wall. mintLifeSafety, mintReports and forCompliance → 0 non-test callers (control mintAdmin → 5). check-raw-store-importers.ts executed → 121 + 2 = 123 importers across two raw storesp5-importers
G14Declared double-send risks already written into the code and not yet closedtemporal/activities/promise.ts:615-624; turnover-workflow.ts:403; collections-chase.ts:1224p10-core-outcomes plus the originating Phase 9 rows
G15The harness registry named as authoritative does not exist; the one that runs cannot hold an ST idOPERATING-CONSTITUTION.md:86 vs 0 files; manifest.json grep -c "ST-" → 1p10-core-replay (ST-938) and the driver
G16Two docblocks assert a property the code no longer hasscope/__tests__/fleet-scope.test.ts:276 says authorizeAddressedWrite "HAS NO PRODUCTION CALLER TODAY" — src/app/api/vendors/route.ts:183 is one. The same claim sits in p7-actor-view's own ref #8337p7-actor-view

8 · Controls discipline — what this page could and could not see

Executed, not inspected — both commands, in a worktree pinned at the sha

Two categorical overreaches, found by a monitor review and corrected on this head

These deserve more space than the searches, because in both cases the individual measurements were right and the sentence built on them was not.

Vacuous controls found — three in the instruments, three in the tests

9 · What this page does not claim

PropFlow Docs