Skip to content

fix(objectql): cut the tenant-audit control's scope by the object's tenancy, not the caller's flag (#13491) - #13635

Merged
zhuangjianguo merged 3 commits into
mainfrom
claude/issue-13491-tenancy-by-object-classification
Aug 31, 2026
Merged

fix(objectql): cut the tenant-audit control's scope by the object's tenancy, not the caller's flag (#13491)#13635
zhuangjianguo merged 3 commits into
mainfrom
claude/issue-13491-tenancy-by-object-classification

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#13491

Implements the maintainer's 2026-08-31 re-ruling (联案 #13491 + #13497, verbatim「同意」, option C): the tenant-audit control's scope is cut by the object's tenancy classification, never by the caller's isSystem flag.

Zone 2 — the PM's assumption, FALSIFIED. This is a build, not an unblocking.

The dispatch expected that narrowing the blanket guard would be "mostly deleting a short-circuit", so tenant-scoped sys_* objects fall through into machinery that already exists. Measured, it is not.

applySystemFields (registry.ts) provisions the organization_id COLUMN unconditionally — its existence was deliberately decoupled from whether tenancy is on, so sudo writers can always stamp it. AST census of every ObjectSchema.create under packages/:

populationcount
platform-namespace objects registered in this repo84
resolve NO tenant field (24 managedBy: 'better-auth', plus sys_sso_provider's tenancy.enabled: false)25
carry a tenant column ⇒ would enter derive/refuse if the guard were simply deleted59

The 84 reconcile exactly against the curated PLATFORM_OBJECTS_BY_PACKAGE registry (89 names minus the 5 cloud-runtime objects defined in the separate repo).

sys_permission_set — the object #8672 reasoned about and the ruling names verbatim as the case whose reasoning inherits — is one of the 59. So deleting the short-circuit replaces a wholesale exemption with a wholesale inclusion, which is the same defect mirrored. The derive branch would additionally stamp an organization onto rows that land org-less today, i.e. a change to what a write stores — forbidden by execution point 3.

The downstream machinery itself needs no new capability: resolveSystemInsertOrganization already reads the schema, resolves the tenant field, checks the rows, reads the posture and reaches #8844's refusal including the multi-organization branch. What was missing is the classification, and its second half ("有列且有写手填") is a fact about the code, not a runtime fact. That is what this PR builds.

What lands

A hand-adjudicated inventory, packages/objectql/src/tenancy/platform-object-tenancy.ts, and two gates narrowed by that one reading:

  1. resolveSystemInsertOrganization's if (isPlatformNamespaceObject(object)) return undefined; becomes if (isPlatformObjectOutOfTenantAuditScope(object)) return undefined; — an admitted object now reaches the derive/refuse machinery.
  2. The engine's bypassTenantAuditisSystem mute, which used to silence every elevated write whatever the object was. The tenant-audit: the "write without tenantId" signal is a throttled log warn gated on multi-tenant posture, so it cannot fire in any environment where code is exercised #13178 census measured 135 of 175 write call sites (77%) silenced at it — the control's largest gate, sitting ahead of the condition the control is about. It now mutes only where the object is not tenant-scoped. An explicit caller-supplied bypassTenantAudit: true is still honoured; this branch only ever filled a gap.

isPlatformNamespaceObject survives as a NAME-SHAPE predicate with a warning against using it for tenancy, and its module header now records the withdrawal rather than the withdrawn doctrine.

Diff surface: engine only. The dispatch expected engine + driver. No driver change was needed: SqlDriver.auditMissingTenant reads the option the engine produces, so narrowing the producer is the whole change. Nothing under packages/spec/src/**.

The one-time inventory (execution point 2)

Admitted — tenant-scoped (7). The admission bar is a citable writer fact: a maintainer-ordered organization repair, a ruled writer that stamps the column, or both.

objectevidence
sys_filewriter repaired to thread the session organization (metadata-store.ts); maintainer-ordered backfill, 2026-08-28
sys_upload_sessionstore stamps from context.tenantId on insert and update; pre-repair rows ruled forward-stamp-only
sys_approval_requestwriter stamps from the subject record's organization; maintainer backfill order 2026-08-23
sys_approval_actionchild row, moves with its parent in the same order; approval-service.ts stamps it
sys_approval_approverchild row, same order; approval-service.ts stamps it
sys_automation_runsuspended-run-store.ts resolves and stamps via recordOrgResolver.organizationOf(...)
sys_notification_deliverySqlOutbox.enqueue writes the derived notification organization

Adjudicated global (1).sys_permission_set — named verbatim by the ruling as the case whose reasoning inherits. ⚠️ Recorded honestly in the ledger: ensure-default-organization.ts DOES stamp org-scoped permission sets, so the object holds both populations. The verdict rests on the maintainer naming it, not on an absence of org-scoped writes.

⛔ Cannot determine — 51 objects, listed rather than guessed. Per「判不了的逐个列出回批呈裁,⛔ 不猜」these keep TODAY'S behaviour exactly and return for adjudication:

sys_activitysys_approval_delegationsys_approval_tokensys_attachmentsys_audience_binding_suggestionsys_audit_logsys_business_unitsys_business_unit_membersys_capabilitysys_commentsys_emailsys_email_templatesys_flow_dispatchsys_http_deliverysys_import_jobsys_inbox_messagesys_invitationsys_jobsys_job_queuesys_job_runsys_membersys_metadatasys_metadata_activationsys_metadata_auditsys_metadata_commitsys_metadata_historysys_migrationsys_migration_journalsys_notificationsys_notification_preferencesys_notification_receiptsys_notification_subscriptionsys_notification_templatesys_positionsys_position_permission_setsys_presencesys_record_sharesys_report_schedulesys_saved_reportsys_scim_connection_credentialsys_secretsys_settingsys_setting_auditsys_share_linksys_sharing_rulesys_teamsys_user_permission_setsys_user_positionsys_user_preferencesys_view_definitionsys_webhook

Plus the 5 cloud-runtime objects (sys_app, sys_environment, sys_environment_member, sys_package, sys_package_installation), which are defined in the separate cloud repository and are therefore structurally unclassifiable from this tree.

A long unknown list does NOT make the blast radius unknowable, which is why this did not trip the STOP condition: unclassified is byte-identical to today's behaviour, so the set of objects whose behaviour moves is exactly the admitted seven.

Three findings inside the unknown list that the adjudicating batch should see first

Direction (execution point 3) and the flips

What this adds is refusals and warnings only. No write's target or payload changes, nothing was skipped, disabled, quarantined, allow-listed, deleted or re-baselined, and no behaviour was rewritten to keep a suite green.

Expected reds registered as flips: none materialized. Reported as a measurement, not as an absence of checking — every suite that owns an admitted object was executed and stayed green (below). The reason is structural: unclassified moves nothing, and the admitted objects' suites either carry an organization or run on a non-walled posture. One prose site DID have to move, and it is the honest half of the same coin: system-write-organization.test.ts justified its exclusion case as "platform namespace ⇒ deliberately org-less (#8672)", the wholesale reading the ruling withdrew. The assertion is unchanged; the comment now says the verdict is unclassified, pending adjudication.

Verification — all at e486ce8163

  • pnpm --filter @objectstack/objectql testTest Files 249 passed (249), Tests 4306 passed (4306)
  • pnpm --filter @objectstack/objectql typecheckDone
  • consumer suites owning the admitted objects, all green: service-storage 518 passed, service-messaging 301 passed, service-automation 1092 passed, plugin-approvals 632 passed, plugin-audit 323 passed, driver-sql 2248 passed | 132 skipped
  • gate family re-derived at the final commit by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack. It grew from 16 families to 39 once the diff took in content/docs/** and scripts/** — all 39 measured green. Four of them first reported PREREQUISITE NOT MET (spec:docs, spec:skill-examples, lint:doc-formula-expressions, lint:doc-security-posture): each reads compiled output that a freshly-recreated worktree does not have. Those are NOT MEASURED, not red — so @objectstack/lint, @objectstack/spec, @objectstack/client and @objectstack/client-react were built and all four re-run green, skill-examples reporting 260 prose examples type-check across 3 surface(s). check:dual-build-cjs-loads still prints PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/; it needs a whole-tree build and is reported as NOT MEASURED, neither green nor red.
  • check:doc-authoring caught a real defect on the first run: the ledger's evidence values are RUNTIME strings, and tracker ids in them reach readers who cannot resolve them (maintainer ruling 2026-08-12). The ids moved to adjacent // comments; the gate is green.

Ablations — mutation and restore both proven on disk

Both mutate the COMMITTED implementation, restore under trap ... EXIT INT TERM with an absolute repo root, and prove the restore by whole-tree git diff HEAD + git status --porcelain plus a HEAD-blob hash match. No rebuild is needed and that is load-bearing: both test files import their subject by relative source path (./engine.js, ./tenancy/platform-object-tenancy.js), not through a package exports map, so vitest reads the mutated source directly and the stale-dist false-green does not apply.

ablationmutation, proven on diskresult
A — restore the wholesale namespace exemptioninjected-marker grep 1, deleted-text grep 0, disk blob bc52fde8 vs HEAD 54c70092exactly the 3 admitted-object derive/refuse pins RED (3 failed / 16 passed); every global/unclassified control and all mute pins stayed green
B — restore the wholesale isSystem muteinjected-marker grep 1, deleted-text grep 0, disk blob f8927518exactly the 2 "no longer auto-muted" pins RED (2 failed / 17 passed); the still-muted controls stayed green

Each ablation reddens only its own gate, which is what makes the two pins independent rather than one assertion counted twice.

The system-context census red — caught by the PM, NOT by the local gate derivation

content/docs/permissions/system-context.mdx anchors objectql/src/engine.tsby line number in 15 places, and the engine commit's +43/-8 shifted every anchor below its change point. Reproduced at 49e2695205: check-system-context-census exit 1, 26 problems over 145 anchors and 109 census sites.

⚠️dispatch-gates.mjs does not name this family — not at the 16-family derivation and not at the 39-family one. Lint & Repo Gates runs it directly and the step is merely named after the first command in it, so there is no pnpm check: alias to find. This is a second instance of the standing reading that the derived family is not the whole farm; PR #13569 hit the same gate for the same reason the same night.

Pure shift was confirmed before --fix was trusted, on both axes the ledger cares about:

  • Population unchanged. The gate reports 109 elevation read sites ... 27 declared non-read before and after — identical. No elevation read site arrived or vanished.
  • 14 of the 15 re-anchored statements are byte-identical across the move, checked line-by-line against git show origin/main:packages/objectql/src/engine.ts.

The 15th is not rot and was not left to --fix: this branch deliberately reworded the exact construct row 24's NON_READ_ANCHORS needle locates — if (isSystem && opts.bypassTenantAudit === undefined) { gained the classification term. The construct still exists and the row still describes it, so the needle was re-pointed at the new spelling before running --fix, since a needle matching zero lines makes the union short by one and --fix would have refused the whole file as a population change. ⛔ No ledger row was added and none retired — it stays shrink-only. ⛔ Nothing was re-baselined and the gate was not quieted.

--fix then rewrote 15 anchors mechanically; the gate is green. Because the script itself was edited, both self-tests were run: check-system-context-census --self-test: all cases passed and isystem-census --self-test green.

Re-run at the final commite486ce8163, not at the commit where the repair landed — the trap that bit #13569, where a later edit shifted a read a second time after --fix had corrected it.

Docs

The PM swept for pages this reclassification falsifies and found none owed beyond those anchors; my own reading agrees. The census page carries no row claiming isSystem exempts organization stamping, and the isSystem claims in field-level-security.mdx / authorization.mdx / execution-context.mdx are about bypassing permission checks, a different control from the tenant-audit one this ruling rescopes. ⛔ Nothing under content/docs/releases/ was touched.

Session for this work: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L


Generated by Claude Code


Generated by Claude Code

…enancy, not the caller's flag
Maintainer ruling 2026-08-31 (联案 #13491 + #13497, verbatim「同意」): the
tenant-audit control's scope is decided per OBJECT, not by the caller's
`isSystem` flag. `isSystem` x a tenant-scoped object is IN scope; `isSystem` x a
genuinely global object is out, with #8672's reasoning inheriting per object
rather than exempting the `sys_`/`cloud_`/`ai_` namespace wholesale.
Two gates narrow by one classification: the blanket
`isPlatformNamespaceObject` short-circuit in `resolveSystemInsertOrganization`,
and the engine's `bypassTenantAudit` isSystem mute (the #13178 census measured
it silencing 135 of 175 write call sites).
The classification cannot be read off the schema: `applySystemFields`
provisions `organization_id` unconditionally, so 59 of the 84 platform-namespace
objects in this tree carry the column, `sys_permission_set` included. The
inventory is therefore hand-adjudicated in
`packages/objectql/src/tenancy/platform-object-tenancy.ts`, with an
`unclassified` verdict that keeps today's behaviour for anything the evidence
does not settle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

github-actionsBot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql, touching 16 documentable anchor(s). ⚠️1 changed file(s) yielded no anchor (packages/objectql/src/tenancy/system-write-organization.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

17 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 575ce836d1c990cb82bb4ba8cb507997d4857a74.

8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/objectql/src/tenancy/system-write-organization.ts) — pages documenting those are invisible to this run
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 15 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 575ce836d1c990cb82bb4ba8cb507997d4857a74packageMentionDocs.

Which tree this was computed on

This run read content/docs from e80bdbbe47b404db1f6290750e5ef03555ecc22e — the merge of head 58f94c112d48ee655fca5c20a060d53d51343768 into base 575ce836d1c990cb82bb4ba8cb507997d4857a74, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e80bdbbe47b404db1f6290750e5ef03555ecc22e && git checkout e80bdbbe47b404db1f6290750e5ef03555ecc22e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 575ce836d1c990cb82bb4ba8cb507997d4857a74 58f94c112d48ee655fca5c20a060d53d51343768 && git checkout -B drift-repro 575ce836d1c990cb82bb4ba8cb507997d4857a74 && git merge --no-ff 58f94c112d48ee655fca5c20a060d53d51343768
node scripts/docs-audit/affected-docs.mjs --json 575ce836d1c990cb82bb4ba8cb507997d4857a74

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 575ce836d1c990cb82bb4ba8cb507997d4857a74 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…ne edit
`content/docs/permissions/system-context.mdx` anchors `objectql/src/engine.ts`
by line number in 15 places, and the tenancy-classification commit shifted every
anchor below its change point. 14 of the 15 are pure line rot — the anchored
statement is byte-identical across the move — and are repaired mechanically by
`node scripts/check-system-context-census.mjs --fix`.
The 15th is not rot: this branch deliberately reworded the construct row 24's
`NON_READ_ANCHORS` needle locates, `if (isSystem && opts.bypassTenantAudit ===
undefined) {`, by adding the classification term. The construct still exists and
the row still describes it, so the needle is re-pointed at the new spelling
rather than left to rot off. ⛔ No row was added and none was retired — the
ledger stays shrink-only, and the gate reports the same population as before the
change: 109 elevation read sites, 27 declared non-read.
Found by the PM, not by the local gate derivation: `dispatch-gates.mjs` does not
name this family, which is a second instance of the standing reading that the
derived family is not the whole farm.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@zhuangjianguoClaude

Copy link
Copy Markdown
CollaboratorAuthor

⛔ CI red — root-caused, and it is not this PR's to fix. Standing down on it, not silently.

domain:engine lane PM. Recording this per the rule that a stand-down is never silent.

The failing check

Test Core (6/6)@objectstack/core:

FAIL packages/core/src/security/authz-store-unavailable.test.ts
> [#13279] every transport that authorizes through resolveAuthzContext
> CONTROL: the scanner finds transports at all, and finds THIS repo
Error: Test timed out in 5000ms.

Tests 1 failed | 1134 passed (1135). The shard then aborted, so 7 of its 8 scheduled packages never ran.

Why it is not this PR's

This PR touches packages/objectql/**, content/docs/permissions/system-context.mdx and scripts/check-system-context-census.mjs. It does not touch packages/core at all, and nothing in the diff relates to authorization transports.

The actual mechanism — read from the test, not guessed

functiondiscoverTransports(): string[]{returnwalk(join(REPO_ROOT,'packages')).filter((f)=>readFileSync(f,'utf8').includes('resolveAuthzContext({'))

It walks all of packages/ and synchronously reads every file, under vitest's default 5000 ms, and it is called twice in the file (CONTROL and SET EQUALITY) with no caching. The cost is O(size of packages/), paid twice, against a fixed budget.

⇒ It slows down as the monorepo grows, and reddens whichever PR happens to be pushing when it crosses the line.

⚠️ The honest part: this PR is not cleanly exonerated

I am not claiming a clean "not mine". This PR adds two files and 648 lines under packages/objectql — a tree that scanner walks and reads. It may well be the straw. What it is not is the defect: the defect is a full repo scan, done twice, uncached, under an inherited default timeout.

⛔ Repairing it here would mean editing a packages/core test from a PR about tenancy classification — widening the PR into an unrelated package. That is not the right shape.

What I did instead

⭐ Recorded because it belongs on the record: this test came from #13475, one of this lane's own landings tonight (the #13279 work this seat reviewed and released). The flake generator is ours.

Everything else on this head

Lint & Repo Gates — the census gate that red-lit the previous head — is running again after the seat's repair, which I verified: all 12 engine.ts anchors now resolve to real isSystem read sites, and the NON_READ_ANCHORS needle edit is the gate's prescribed repair for a stale needle (new needle matches exactly 1 line, old matches 0, row count 27 → 27, needle got longer). No other check is red.


Generated by Claude Code

@zhuangjianguoClaude

Copy link
Copy Markdown
CollaboratorAuthor

Test Core (6/6) is not this PR's failure — standing down on it, once

Failing check:Test Core (6/6) (job 99383528099) in run 33357913478, red at 04:44:01Z.

FAIL packages/core/src/security/authz-store-unavailable.test.ts
> [#13279] every transport that authorizes through resolveAuthzContext
> CONTROL: the scanner finds transports at all, and finds THIS repo
Error: Test timed out in 5000ms.
❯ src/security/authz-store-unavailable.test.ts:214:3

Tracked as #13645, now claimed and dispatched by this lane.

Why it is not this PR's

This PR changes packages/objectql, content/docs/permissions/system-context.mdx, scripts/check-system-context-census.mjs and a changeset. It does not touch packages/core.

The obvious objection — "but this PR adds files, and #13645's mechanism is that the test walks a tree that grows" — was the honest worry when #13645 was filed, and the card recorded it as unestablished. It is now settled, against that reading. The identical failure hit #13630 at 04:33:56Z, eleven minutes earlier, in its merge_group run 33357337261. #13630 adds zero new files under packages/ (it modifies two existing .ts files and adds one .md changeset outside the walked tree), and because this PR is still open, that queue branch is main + #13630 alone and contains none of this PR's files.

walk() enumerated the same file set as plain main, and still blew the 5000 ms budget. main is already over the line. This PR did not cross it and cannot be made to un-cross it.

⛔ Not spending a re-run

The failure mode is monotonic, not random — the cost grows with the tree and there is nothing to re-roll — so a re-run re-fails by construction. "Flake" was never the root cause. The one sanctioned re-run stays unspent on this PR. (An earlier attempt returned 403 "This workflow is already running" while sibling jobs were in flight; that attempt is moot now that the cause is established by two independent reproductions.)

Not yet settled on this PR

Run 33357913478 is still in progressTest Core (1/6) and Lint & Repo Gates had not completed at the time of writing. This comment stands down on Test Core (6/6)only. Lint & Repo Gates carries the check-system-context-census gate that the last commit (e486ce8163) repaired, and if that or any other check comes back red, it is this PR's to root-cause and will be handled as such — no part of this comment excuses it.

Release is blocked on #13645 landing regardless, since Test Core (6/6) cannot go green before it. Still watched.


Generated by Claude Code

@zhuangjianguoClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM verdict: ACCEPT — blocked on #13645 alone, not on anything in this PR

Run 33357913478 is now complete at e486ce8163. My previous comment stood down on Test Core (6/6) while two jobs were still in flight, and said plainly that if either came back red it was this PR's to root-cause. Both came back green.

The complete red list is two checks, and they are one failure

checkresult
Test Core (6/6)#13645authz-store-unavailable.test.ts timeout
Test Core (rollup)❌ reflects the above and nothing else
everything else — 27 checks

Green includes Build Core, Build Docs, all four Type Check legs (workspace, source gates, consumer gates, debt ledger), Dogfood Regression Gate ×3 + Dogfood Verify CLI, Temporal Conformance (live PG + MySQL), Check Changeset, Check PR Size, Check Documentation Links, and the three claim/single-writer gates.

⭐ The predicted red materialised and the repair held

Lint & Repo Gates completed success at 04:54:41Z. That is the job carrying check-system-context-census — the gate this seat was warned about before it pushed, on the reading that system-context.mdx anchors objectql/src/engine.ts by line number in 15 places and a +43/-8 edit would shift every anchor below its change point.

It reproduced at 26 problems, exactly as predicted, and the repair is confirmed correct by this green. Worth recording precisely because the gate is not in the dispatch-gates.mjs derived family — this is the second instance of the standing #13333 reading that the derived family is not the whole farm.

I also re-verified the one hand-edited NON_READ_ANCHORS needle independently before this run: the new needle matches exactly 1 occurrence, the old matches 0, row population is 27 → 27, the needle got strictly longer, and why is unchanged. That is a tightening, not a weakening — the ledger stays shrink-only and no row was added or retired.

Release status

Not released, and not being marked ready. The enqueue bar in this lane is every check green, not the required subset, and two are red. Marking ready or enqueuing now would only re-run into the same timeout and, if it reached the queue, eject and force a rebuild of everything behind it.

The single remaining blocker is #13645, which is dispatched. It is not this PR's failure, on measurement rather than assertion: the identical failure hit #13630 eleven minutes earlier on a queue branch whose walked file set is identical to plain main — so main was already over the 5000 ms budget before either diff existed.

⇒ On #13645 landing, this PR needs no code change — only a re-run of the two red checks against the fixed base. Still watched.


Generated by Claude Code

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review August 31, 2026 06:27
@zhuangjianguo
zhuangjianguo added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit e49d988Aug 31, 2026
35 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-13491-tenancy-by-object-classification branch August 31, 2026 06:53
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

design: isSystem 写入是否在租户审计控制范围内?——#13178 类级装置(A/B/C)的共同前置,从未被裁过

2 participants

@zhuangjianguo@claude