Repository navigation
fix(platform-objects,core): sys_metadata_activation ships tenant-less — drop the reserved organization_id before 17.3 is cut (ADR-0126 amended by ADR-0131 D6/D7) #15024
Description
Activity
- addedpriority:p1High: required for production / M2High: required for production / M2
on Sep 3, 2026 Blocked-by: #15023
Unlock-action: re-check card #15024
pm:queue→pm:blocked— the card's own blocker is not yet satisfieddomain:servicesexecution seat, sessionsession_01AUF1NoViznQK32gqpK8wS8. Read-modify-write with the read immediately before the write; comparative read-back againstunion(current, target)={priority:p1, domain:services, target:v17, pm:blocked}— matched.⛔ Not a disagreement with the ruling, and not a re-grading.
priority:p1,target:v17and the 17.3 deadline all stand exactly as filed. This is only the state label catching up with what the body already says.Measured just now: the body carries
Blocked-by: PR #15023 (ADR-0126 Superseded), and PR #15023 isstate: open,draft: true— unmerged. ADR-0126 is therefore not yet marked Superseded onmain.That matters because this card's own acceptance depends on it:
pnpm check:adr-anchorsgreen (ADR-0126 is Superseded, so its code anchors are no longer required)⇒ Dispatching before #15023 lands would send a dev at a gate that is supposed to be red, on a premise that is not yet true.
pm:queuealso advertises the card as dispatchable to every other reader of the queue, which it is not.⚠️ This does not slow the 17.3 work down. The two revert cards are independent: #15030 (theplugin-sharingNULL-inclusive unit screen) has no blocker, its premise was verified onorigin/main, and it is dispatched now — claim comment on that card. This one starts the moment #15023 merges, and theBlocked-by:line above puts it in the mechanical unlock scan's reverse index so it is not left to memory.⚠️ One thing for whoever picks it up, measured here so it is not re-derived: my own grep for anadr-0126file onorigin/mainreturned nothing, but ⛔ do not read that as "the ADR does not exist" — my pattern may simply not match the repo's ADR filename convention, and a zero with no positive control is not a reading. Confirm the ADR's actual path and status directly before relying on it.
Generated by Claude Code
⏸ On hold — do not start. The maintainer is reconsidering whether ADR-0126 is superseded or amended (2026-09-04, live chat: 「所以 ADR-0126 不能简单的关掉」). The disable half of the packaged-flow machinery may be kept as environment-level operational state (tenant-less activation ledger, consistent with the proposed ADR-0131 D7) rather than reverted. This card is re-scoped or closed once that ruling lands; until then
pm:queueis withdrawn.🤖 Generated with Claude Code
- changed the title
[-]revert(automation,core,platform-objects): remove the unreleased ADR-0126 flow/action disable + clone machinery before 17.3 is cut (ADR-0126 superseded by ADR-0131)[/-][+]fix(platform-objects,core): sys_metadata_activation ships tenant-less — drop the reserved organization_id before 17.3 is cut (ADR-0126 amended by ADR-0131 D6/D7)[/+]on Sep 4, 2026 ▶ Re-scoped and back in the queue. No longer a revert: the ADR-0126 machinery ships in 17.3; this card only drops the reserved
organization_idfromsys_metadata_activationso the ledger is tenant-less (ADR-0131 D7). Body rewritten above; the hold comment is superseded.🤖 Generated with Claude Code
1 remaining item
Claim: PM loop — maintainer direct-dispatch channel (2026-08-10 standing authorization). Verbatim instruction, 2026-09-04, live chat: 「同意,现在开始派发 17.3 相关的开发任务」— this card and #15030 named; #15030 was found already landed by the
domain:servicesseat (PR #15078, merged 2026-09-03T21:43Z), so this is the only dispatch under that instruction.
Session:6679d191-11f4-465b-b322-0e0409d76793(the ADR-0131 drafting session; PM branchclaude/discussion-13564-a38847)
Branch:claude/issue-15024-activation-ledger-tenantless
Worktree:objectstack-issue-15024
Domain:domain:servicesas labelled.⚠️ File surface ispackages/core+packages/platform-objects, which the lane table anchors todomain:engine; label left as filed (routing is triage's), direct channel — this is not a lane claim.
File surface:packages/platform-objects/src/system/sys-metadata-activation.object.ts(+ its test),packages/core/src/utils/metadata-activation-store.ts(+ test), any migration/index naming the column onsys_metadata_activation, one changeset (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: opus—node scripts/pm/dispatch-gates.mjs --tier <paths>(run at claim time): "no path-derived mandate … floor sonnet · default opus · ceiling fable"; judgment call = default opus (a schema declaration plus a store read-path change, tested against the operator gate and theexecute()consult)
Clause-②: no — no contract accept/reject behaviour changes and no public surface widens; an injected column is removed from an object that has never shipped (landed after the 17.2.0 tag)
Serial constraints cleared: none — no open PR touches the two files (REST search 2026-09-04); thedomain:servicesseat's three in-flight cards (#14333/#14712 service-automation, #14530/#14718 plugin-security, #14373 plugin-auth) share no file; #15078 (already merged) touched plugin-sharing onlyClaim: os-dev for #15024
Session:
6679d191-11f4-465b-b322-0e0409d76793(os-dev subagent under the PM dispatch session of the same id;mode:subagent,model: opus)
Branch:claude/issue-15024-activation-ledger-tenantless
Worktree:/Users/zhuangjianguo/Documents/GitHub/objectstack-issue-15024, basefcc42e6c1de9df5c65ab60166bf15c3aeea5bfe2(origin/mainat claim time)
Branch pushed empty before the first edit — the write route is confirmed (* [new branch]), so a push failure cannot surprise this card at the end.Thread re-read after posting: the only prior
Claim:comment is the PM's (5535145439) and it names this same branch. No competing claim.Scope taken as filed: drop the reserved
organization_idfromsys_metadata_activation(declaration + store read filter + the docblock that reserves it), rewrite the pins onto the column's absence. The ADR-0126 machinery, the operator gate and theexecute()/ dispatch-time consults are untouched and stay pinned.🤖 Generated with Claude Code
os-dev-report
{ "issue": 15024, "status": "done", "branch": "claude/issue-15024-activation-ledger-tenantless", "pr": "https://github.com/objectstack-ai/objectstack/pull/15155", "head_sha": "35ed1e10743f6c90a3f590c421a5387e2707578c", "premise_still_valid": true, "files_changed": [ "packages/platform-objects/src/system/sys-metadata-activation.object.ts", "packages/platform-objects/src/system/sys-metadata-activation.object.test.ts", "packages/core/src/utils/metadata-activation-store.ts", "packages/core/src/utils/metadata-activation-store.test.ts", "packages/objectql/src/action-activation.ts", "packages/objectql/src/action-activation.test.ts", "packages/services/service-automation/src/engine.ts", "packages/services/service-automation/src/flow-activation-store.ts", "packages/services/service-automation/src/flow-activation-ledger.test.ts", "packages/runtime/src/domains/actions.ts", "packages/runtime/src/domains/activation-gate.ts", "packages/qa/dogfood/test/packaged-activation-ledger-reach.dogfood.test.ts", ".changeset/activation-ledger-tenant-less.md", ".changeset/sys-metadata-activation-ledger.md", ".changeset/ledger-convergence-registration-and-one-store.md" ], "summary": "sys_metadata_activation now ships with no tenant column: the object declares systemFields.tenant false and no longer declares organization_id, the declared unique index states unique 'global' over (metadata_type, name), and ObjectStoreMetadataActivationStore drops both the NULL read filter and the org-row skip. A1 was FALSIFIED in a load-bearing direction and changed the fix: the column was EXPLICITLY declared on the object, not injection-only, so deleting the field alone would have left the column in place via applySystemFields; both halves were required. Nothing in the ADR-0126 machinery is reverted or weakened, and A5 held: no consult seam reads the column in code (every hit outside the two implementation files was docblock prose), so the operator gate and both consult seams pass unchanged.", "tests": "All results from head_sha 35ed1e107, working tree clean at it. ACCEPTANCE GREP: `git grep -n organization_id -- packages/core/src/utils/metadata-activation-store.ts packages/platform-objects/src/system/sys-metadata-activation.object.ts` => EXIT=1, no hits; positive control = same pattern returns 3 hits on sys-sso-provider.object.ts. COLUMN GONE FROM EMITTED SCHEMA, read not inferred: (a) resolveInjectedSystemColumns(SysMetadataActivation) reports tenant:false and a names set without organization_id, anti-vacuity assertion is that the same set still contains 'id'; (b) real booted stack (dogfood, 11/11) - the row returned by the driver's own SELECT has no organization_id key, anti-vacuity asserts the same key set contains id/metadata_type/name/active. ABLATION: removing the systemFields line turns the new pin RED - 'AssertionError: expected true to be false', 1 failed / 14 passed; mutation confirmed on disk BEFORE the run (anchor occurrences 1 -> 0 and git hash-object changed), restore proven AFTER (git diff HEAD empty; working blob hash == HEAD blob hash, 3050a5bc on both sides), under trap ... EXIT INT TERM with absolute paths. No rebuild leg was needed or claimed: vitest resolves that file from SOURCE via a same-package relative import, not through exports->dist. NEVER SHIPPED, measured: git merge-base --is-ancestor shows the fix is NOT an ancestor of @objectstack/account@17.2.0, positive control @objectstack/account@17.2.0~1 IS (predicate can answer YES); the object's adding commit 428f9b24a (2026-08-25) is NOT an ancestor of the tag (2026-08-23). SUITES all green: objectql 269 files/4616 tests, runtime 220/3160, service-automation 103/1225, core 48/1159, platform-objects 33/518, dogfood ledger-reach 1/11. TYPECHECK green for core/platform-objects/objectql/runtime, and check:test-typecheck compiled the TEST LAYER in each ('check:test-typecheck: OK - ...'s test layer compiles under tsconfig.test.json'), so the rewritten pins were genuinely type-checked. SEAMS UNCHANGED: isolated-posture operator gate passes incl. 'REFUSES a tenant org admin, loudly, and never writes the row' and 'ALLOWS the platform operator'; execute() seam passes incl. 'refuses a disabled record-change flow with FLOW_DISABLED, and re-enabling restores firing' and 'refuses on the SUBFLOW entry path'.", "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed; derived from merge-base) => 48 families, exit 0", "measured_green": 47, "not_measured": 1, "red_from_this_diff": 0, "verdict_lines_quoted": [ "check:dual-build-cjs-loads: 'check:dual-build-cjs-loads - 102 published require entry point(s) across 66 package(s) load; 610 emitted CommonJS file(s) parse; 1 cross-format behaviour probe(s) agree; 100 require condition(s) resolve a CommonJS-flavoured types that exists.'", "check:published-readme-exports: 'check:published-readme-exports - 60 published document(s) across 79 workspace package(s); 213 import statement(s), 51 workspace type entr(ies), 198/198 @objectstack/ specifier(s) naming a workspace member.'", "check:cross-package-test-inputs, check:nul-bytes, check:engine-double-contract, check:test-source-alias, check:objectql-double-limit, check:changeset-gate-self-tests, check:doc-authoring, check:published-files, check:route-envelope and 36 others: exit 0, captured by redirecting to a file BEFORE reading the exit code (never through a pipe)" ], "not_measured_detail": "@objectstack/spec check:react-declaration-parity - its own words: 'MANIFEST is not set - there is no registry side to compare against. This gate did NOT run.' It needs an sdui.manifest.json dumped from a sibling objectui checkout. Environmental and unrelated to this diff; it entered the family list only because the dogfood test path matches a broad packages/qa/dogfood/** CI trigger. Reported as NOT MEASURED, not as green and not as red.", "prerequisite_handling": "check:dual-build-cjs-loads and check:published-readme-exports first returned 'PREREQUISITE NOT MET ... nothing was measured' / 'Build first'. Rather than report those as reds, a full `pnpm build --concurrency=2` was run (72/72 tasks) and both were re-run to real green verdict lines." }, "deviations": [ "A1 FALSIFIED (load-bearing, changed the fix): the card assumed the column arrives only by injection with no explicit declaration. It was EXPLICITLY declared on the object as Field.lookup('sys_organization', ...). Deleting the field alone would have left the column, because applySystemFields injects the tenant anchor unless the object opts out. The fix therefore does BOTH: delete the declaration AND add systemFields: { tenant: false }.", "Zone 3's ROUTE was right, its stated REASON needed refining. The card said tenancy.enabled:false 'also carries authorization-posture semantics' while systemFields.tenant:false does not. Measured: BOTH spellings feed the same tenancyDisabled disjunction in plugin-security (security-plugin.ts, two sites), so both stand the Layer 0 wall down - and that is REQUIRED, not a side effect to avoid, since a wall predicating on a non-existent column denies every row. The real distinction is that only tenancy.enabled:false trips the spec's isTenancyDisabled (driver native scoping, sticky per-table opt-out), which this table does not need because computeTenantField already returns null once the column is absent. systemFields.tenant:false remains the correct, minimal key.", "INDEX RESPELLED, not named in the card: unique 'organization' -> 'global'. Required for honesty and DDL-identical. normalizeDeclaredIndex prepends the tenant key part only `if (idx.unique === 'organization' && tenantField)`, so with no tenant column 'organization' already degraded to the same two columns. Left as-is it would have declared a per-organization boundary that does not exist. Kept explicit rather than bare `true`, which lint unique/unscoped-declared-index warns on and protocol 18 rejects.", "ACCEPTANCE GREP vs comments - resolved rather than traded off. The card's acceptance wants that grep to return NOTHING, which would have meant deleting the reasoning that stops someone re-adding the column. Both implementation files therefore name the tenant column IN WORDS instead of as the literal token: the grep returns zero AND the 'why' survives. The grep DOES still hit the TEST files and must - pinning a column's absence requires naming what is absent, and the card's own Scope item 4 asks for exactly those pins. Flagging the tension explicitly rather than letting the PM discover it.", "FILE SURFACE WIDER than the PM's declared list, all in the same defect class and each required by the change: (a) two consumer suites (objectql action-activation.test.ts, service-automation flow-activation-ledger.test.ts) carried 'SKIPS a row carrying an organization_id' pins on behaviour deliberately removed - rewritten to pin the absence, not deleted; (b) row-shape docblocks in action-activation.ts, flow-activation-store.ts, service-automation/engine.ts, runtime/domains/actions.ts and runtime/domains/activation-gate.ts described the removed column; (c) the dogfood assertion had to be inverted or it would have passed VACUOUSLY (undefined ?? null === null) - green for exactly the reason it should have gone red.", "TWO PENDING CHANGESETS CORRECTED (.changeset/sys-metadata-activation-ledger.md, .changeset/ledger-convergence-registration-and-one-store.md). Both are unreleased and describe the reserved column and the org-row skip as shipping behaviour, so left alone they would announce a column 17.3 does not have - in the release notes for the release this card exists to get right.", "docs/adr/0126-packaged-metadata-customization-model.md deliberately NOT edited (5 hits on the column). It is a governed surface and the amendment record is PR #14976's job, not a code PR's.", "ADR-0087 registration NOT required, checked as Zone 3 asked: check-adr-0087-registration.mjs is driven off the changeset's own breaking/major declaration, so a patch changeset demands no ledger entry. The changeset is patch for platform-objects, core, objectql and service-automation.", "os-verify-lock ran in UNLOCKED (declared) mode on this host - verbatim: 'no usable flock on this host, so the shared verify lock was NEVER taken and NOTHING was serialized'. Every heavy command went through the entry point, but none of it was serialized against other agents in this container. Also declared in the PR body as the script instructs.", "dispatch-gates reported STALE TREE: this branch is 2 commits behind origin/main and one file it derives from (scripts/check-type-check-coverage.mjs) changed in that range. That gate is not in the derived family list. I did not rebase.", "PRE-EXISTING RED, not mine: pnpm check:platform-checklist reports 4 UNCLASSIFIED coverage problems (batch_endpoints, crud_endpoints, metadata_endpoints, route_generation). Verified BYTE-IDENTICAL at origin/main fcc42e6c1 in a throwaway worktree before attributing it. That gate is deliberately not wired into CI (maintainer decision, noted in lint.yml)." ], "open_questions": [], "out_of_scope_findings": [ "filed as #15154: the platform-checklist item platform-core.activation-ledger-row-contract is written around the removed column - its step 7 tells the runner to INSERT a row with organization_id set, which can no longer succeed, and its refs cite unique:'organization' / 'reserved-NULL' / 'org-row skip' text that no longer exists in either file. Not fixed in this PR because the replacement is a judgement about what the checklist should assert (retire the org-skip clause, or replace it with a no-tenant-column probe), not a mechanical edit. Deduped first via REST search with a control query that returned 6 hits." ], "mcp_calls": "0 - every GitHub read and write used the gh REST CLI (repo-scoped probe succeeded at the start), so no MCP GitHub calls were spent." }ACCEPT — pending CI convergence. Reviewer of record: the dispatching PM session (
6679d191-11f4-465b-b322-0e0409d76793), maintainer direct-dispatch channel. Verified against GitHub, not against the report's own account.PR #15155 — draft, base
main, body opensFixes #15024, footer present; 15 files, none on a governed surface (docs/adr,.claude,skills,AGENTS.md,CLAUDE.md) and none underpackages/spec—Clause-②: noholds. Path face matches the defect class: the object declaration and its test, the store and its test, the two consumer suites that pinned the removed org-row skip (objectqlaction-activation, service-automationflow-activation-ledger), row-shape docblocks in five files, the dogfood reach test, one new changeset (patch × 4 packages) and two pending changesets corrected so 17.3's release notes do not announce a column 17.3 does not have.Spot-checked in the diff:
systemFields: { tenant: false }added and the explicitorganization_idlookup field removed (the card's A1 assumption — injection-only — was falsified: the column was declared, so both halves were needed; correct call); the declared index respelledunique: 'organization'→'global'(with no tenant column the two spellings are DDL-identical, and the honest one isglobal); the store'sorganization_id == nullfilter and org-row skip removed. Nothing in the ADR-0126 machinery is reverted; the operator-gate andexecute()seam suites are reported green and are re-run by CI's Test Core shards.git merge-base --is-ancestorreadings show the object's adding commit and this fix both postdate@objectstack/account@17.2.0— never shipped, plain removal, no ADR-0087 entry (patch changeset).Deviations, accepted: file face wider than the claim's declared list (all same defect class, each explained); the acceptance grep returns zero on the two implementation files while the TEST files still name the column — required to pin its absence;
docs/adr/0126deliberately untouched (its amendment travels in PR #14976). Out-of-scope finding filed as #15154 (checklist item written around the removed column) — for triage.Landing: the PR is not a governed surface. It goes ready → merge queue as soon as every check on
35ed1e10is green (16 in progress at review time: Test Core shards, Dogfood gates, Temporal Conformance, Build Core).⚠️ Must be merged before the 17.3 tag.🤖 Generated with Claude Code
os-dev-report patch 1
New head sha:
36695cd33ac9a012a3714956dbdb3e1907e1002b(36695cd33), pushed to
claude/issue-15024-activation-ledger-tenantlessas a separate commit on top of
35ed1e107— no squash, no force-push, no rebase, no merge ofmain.Census gate verdict line, re-run at
36695cd33on a clean tree, exit code captured
before any pipe (EXIT=0):check-system-context-census: OK — 106 elevation read sites in 20 packages across 45 files, all anchored; 140 anchors resolve, 27 declared non-read.Before the fix it printed 4 problems over the same population — both directions of the same
rot at once:[site-without-a-row]foractivation-gate.ts:138and:189, and
[anchor-is-not-a-read-site]for the stale:139and:190.Files the fix touched — one:
content/docs/permissions/system-context.mdx(row 56, one line)
Confirmed cause, not inferred: the docblock correction in
activation-gate.tsreplaced a
four-line passage with a three-line one, so bothec.isSystemreads moved up by exactly one
line.node scripts/isystem-census.mjs --jsonreports the two real read sites at 138 and
189; the page still anchored 139/190.--fixrewrote exactly two anchors and nothing else:re-anchored content/docs/permissions/system-context.mdx:167 `activation-gate.ts:139` -> `activation-gate.ts:138` re-anchored content/docs/permissions/system-context.mdx:167 `:190` -> `:189` check-system-context-census --fix: 2 anchor(s) rewrittenThe diff was inspected before committing: a single file, a single line, only the two anchor
numbers changed. The row's behaviour text ("Activation write / authoring refusals do not
fire", the Get/Lose description, the package column) is byte-identical, so no elevation
behaviour claim moved. Nothing outside that file is modified.Re-derived gate families for the enlarged surface (the docs page joins the diff):
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstacknow reports 64
families, 16 newly derived versus the pre-patch run — thecontent/docs/**docs set.
All 16 measured green. Four of them first returned a prerequisite result rather than a
finding, because this worktree had been cleaned up after the PR and rebuilt from scratch:
check:doc-formula-expressionsandcheck:doc-security-postureexit 3, whose own text
says "result says NOTHING about what it gates. It is NOT a finding";check:docsand
check:skill-examplesasked for a spec build first. Afterpnpm build(72/72 tasks) all
four re-ran to exit 0 — e.g.
✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1141 packages/spec/src files.
They are reported as measured green, never as reds.⚠️ Declared, unchanged from the parent report:os-verify-lock.shstill runs in
UNLOCKED (declared) mode on this host — "no usable flock on this host, so the shared
verify lock was NEVER taken and NOTHING was serialized".⚠️ Declared, and louder this round:dispatch-gates.mjsreports STALE TREE — this
branch is now 7 commits behindorigin/main, and 5 files the answer derives from changed in
that range, includingscripts/pm/dispatch-gates.mjsitself. Its own words: "this run
read their old copies and still exited 0 — a well-formed answer about a tree nobody is on."
I did not rebase or mergemain, as instructed — flagging it so the merge queue's rebuild is
the thing that settles it.🤖 Generated with Claude Code
Landing. CI on
36695cd33converged fully green (32 success / 2 skipped / 0 red). Governed-face predicate re-run on the final 16-path file list: NOT governed. PR #15155 flipped ready 04:35:43Z, auto-merge enabled 04:35:49Z,added_to_merge_queue04:37:18Z (queue confirmed live — it landed five PRs around 03:40Z). This card closes viaFixes #15024when the queue merges; the landing readback (merged sha + main head) follows here.🤖 Generated with Claude Code
Landed. PR #15155 merged by the queue at
2026-09-04T05:03:46Z; merge commitefb351317isorigin/mainHEAD (git merge-base --is-ancestor— yes). This card auto-closed viaFixes #15024.pm:dispatchedstripped in a read-modify-write with comparative read-back;domain:services,priority:p1,target:v17remain (routing and severity are not state). 17.3 is not yet tagged (@objectstack/account@17.2.0is still the latest), so the pre-17.3 condition of ADR-0131 D14 is met for this card:sys_metadata_activationships tenant-less. Follow-up finding #15154 (checklist item written around the removed column) stays with triage.🤖 Generated with Claude Code
- added 3 commits that reference this issue
on Sep 9, 2026
Re-scoped on the maintainer's ruling (2026-09-04, live chat: 「所以 ADR-0126 不能简单的关掉」「hotcrm 是标准的软件包,客户安装之后能根据业务需求实现具体的定制」「同意」). ADR-0126 is amended, not superseded (PR #14976, ADR-0131 D6): its regimes stand at environment scope and the packaged-flow / packaged-action disable + clone machinery ships in 17.3. What does NOT ship is a nullable tenant column on a new table.⚠️ Must land before the 17.3 tag.
业务一句话
ADR-0126 的活化账本
sys_metadata_activation是「本环境把哪个受管流程关掉了」这种部署级状态,不属于任何组织。它今天带着一个「预留、先写 NULL」的organization_id列,正是 ADR-0131 要消灭的形状。发版前把这列去掉,让这张表以无组织列的部署级状态表出厂。Scope
sys_metadata_activation(packages/platform-objects, declared by feat(platform-objects): declaresys_metadata_activation, the ADR-0126 §4 activation ledger #12185) declaressystemFields.tenant: false; the store (packages/core/src/utils/metadata-activation-store.ts, Ledger convergence: registration home + one store implementation (ADR-0126 §4/§8, maintainer-ruled) #12419) drops itsorganization_id == nullfilter and the "RESERVED, never written" docblock — there is no column to reserve.execute()-time consult (feat(automation): durable packaged-flow disable — activation ledger, execute() consult, operator gate #12296) are untouched and stay pinned.⛔ Do not revert #12185 / #12190 / #12296 / #12348 / #12419 / #12491 — that was this card's first scope and is withdrawn. ⛔ Do not touch
sys_metadata, ADR-0005's overlay path or the permission-set write-through — v18, ADR-0131.Acceptance
git grep -n organization_id -- packages/core/src/utils/metadata-activation-store.ts packages/platform-objects/src/**/sys-metadata-activation*returns nothing; the DDL forsys_metadata_activationhas noorganization_id; automation / core / platform-objects suites green; disabling a packaged flow on anisolatedrig still requires the operator capability and still refuses atexecute(); the fix commit is confirmed NOT an ancestor of@objectstack/account@17.2.0(positive control: one 17.2.0 commit IS).Refs: ADR-0131 (PR #14976) D6 / D7 / D14 · ADR-0126 D2 / D3 · #12155 · #12419 · #13564.