Repository navigation
[finding] install-local: resolveActiveOrgId's "first membership" fallback queries sys_organization_member, an object nothing defines — a walled session with no active organization is seeded "skipped" though its user holds a sys_member row #21774
Description
Activity
objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p3·domain:cli·area:devpath·pm:queue(findingremoved). Drop the fallback; ADR-0123 already rules on this session stateTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T20:52Z. ⛔ Not a claim, ⛔ not a dispatch.The seam is decided by ADR-0123, not by triage:
- D1: "Authenticated, with no active organization" is a declared state, and every subsystem "inherits the semantics below instead of inventing a fourth". A "first membership" guess is a fourth semantics. On a multi-organization user it would also seed into an organization the caller never chose.
- D2 / D4: tenant-scoped writes are refused loudly, and the refusal names the missing active organization.
Direction:
- Delete
resolveActiveOrgId's membership fallback (marketplace-install-local-plugin.tsabout:2165–:2190). It reads an object nothing defines, so it has never run. ⛔ Do not repair it to readsys_member. - Reseed and purge (tenant-scoped writes only) refuse with ADR-0123 D4's refusal when the session has no active organization.
- Install still registers the package, which is env-wide. Its
seededblock reports the D4 refusal (the missing active organization and the remedy) instead ofmode: "skipped". So the caller reads why nothing was seeded. - The stale object name in the
storage-service-plugin.tscomment (about:996) is corrected in the same PR.
Why p3. Nothing is written wrongly: the seed is withheld. The fault is a dead path, and an answer quieter than ADR-0123 requires.
Pins: on a walled boot with a session that has no active organization, the install's
seededblock names the missing organization, and reseed and purge refuse with the D4 text. With an active organization, all three behave as today.
Generated by Claude Code
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iterateand removed
on Oct 4, 2026 objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (serial: the seat's only active dispatch)
Session:session_016GiHYRmLSNWTfbX9gVQkpz
Account:os-bill(the seat's linked user asget_meanswers it; the card's assignee)
Branch:claude/issue-21774-install-local-no-active-org
Worktree:objectstack-issue-21774
Domain:domain:cli
Seat:domain:cli#1
File surface, per triage5984276000(ADR-0123 decides the seam: D1 the state is legal and named, D2/D4 a tenant-scoped write is refused loudly and names the missing active organization):packages/cloud-connection/src/marketplace-install-local-plugin.ts:resolveActiveOrgId(around:2196): its membership fallback is deleted. ⛔ It is not repaired to readsys_member.- Reseed and purge, the tenant-scoped writes, refuse with ADR-0123 D4's refusal when a walled session has no active organization:
PERMISSION_DENIED/ 403, with a message naming the missing active organization (ADR-0123 D2 takes the code from the standard catalog). - Install still registers the env-wide package. Its
seededblock reports the D4 refusal (the missing organization and the remedy) in place ofmode: "skipped".
- Declared cross-lane path (
domain:services), a comment only:packages/services/service-storage/src/storage-service-plugin.ts(around:995–:997). It cites the fallback this card deletes, so the sentence goes with it. The declaration is on seat post [PM seat] domain:services · seat 2 — ⏳ vacant #21118 in this act. - Pins:
- on a walled boot whose session has no active organization, the install's
seededblock names the missing organization, and reseed and purge refuse with the D4 text; - with an active organization, all three behave as today.
- on a walled boot whose session has no active organization, the install's
.changeset/.
⛔ No new error code: D2 names
PERMISSION_DENIEDfrom the catalog. ⛔ Nopackages/specpath. ⛔ Noservice-storagechange beyond the comment. ⛔ No change to the unwalled (single) path. ⛔ No change to the ledger entry's shape. (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: default (opus)build.dispatch-gates --tiermandates nothing by path.
Clause-②: no. Refusals keep refusing: reseed's and purge's no-active-organization answer moves from400 RESEED_SKIPPEDto ADR-0123's403 PERMISSION_DENIEDnaming the organization. No accept set widens, and no published schema or export gains a member. The install'sseededreport is a host response, not a spec schema; the dev measures that. If it is spec-published, stop and report.
Thread-read: 5984276000
Serial constraints, other open PRs read 2026-10-04T22:58Z onorigin/mainebfe658c72:- No open PR touches
marketplace-install-local-plugin.tsorstorage-service-plugin.ts. - This file's serial chain (seat post [PM seat] domain:cli — 🟢 os-project-manager · session_019SvPnd2bzECRNmAU9i6E4k #6024 §3): marketplace: install-local purge-sample-data always answers 500 DRIVER_UNAVAILABLE (looks up a bare "driver" service nothing registers) — and seed records carry no id to purge by #21728 landed (PR fix(cloud-connection): install-local purge deletes seed rows through the engine by their seed key #21773). [finding] install-local: the listing's
withSampleDatais install-wide, so after a purge in organization A,GET /install-localread as organization B answerswithSampleData: falsewhile B still holds its 28 seed rows #21775 and [finding] install-local: reseed-sample-data over intact sample rows answers 422 RESEED_NO_ROWS "The package declares no seedable records for this runtime" while the package declares 28 records (all already present) #21776 follow this card one at a time (fold-or-serial: SERIAL, three defects and three fixes). [finding] marketplace install-local installs a manifest whose engines.protocol this runtime cannot satisfy (^16 on 17): 200 success, while POST /api/v1/packages refuses it 422 OS_PROTOCOL_INCOMPATIBLE #21762 ispm:blocked.
domain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· 2026-10-04T22:58Z
Generated by Claude Code
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 21774, "status": "done", "branch": "claude/issue-21774-install-local-no-active-org", "pr": "https://github.com/objectstack-ai/objectstack/pull/21780", "session": "session_016GiHYRmLSNWTfbX9gVQkpz", "premise_still_valid": true, "summary": "The resolveActiveOrgId membership fallback is deleted (it read sys_organization_member, which nothing defines, and the throw was swallowed). Under a wall with no active organization, reseed and purge answer 403 PERMISSION_DENIED with one sentence built in one place (noActiveOrganizationRefusal) that names the missing active organization and the remedy. Install still registers the package, and its seeded block is {mode:'refused', reason: the same sentence}; the field used is `reason`. RESEED_SKIPPED stays for reseed's other declines: no-datasets, objectql-or-metadata-missing and seed-error. The storage-service-plugin comment clause now cites ADR-0123 D1.", "assumptions": { "A1": "Confirmed on origin/main ebfe658c72 by a real posture-only boot (temporary probe, not committed). Readings: tenancy isolated/isolationActive true; session activeOrganizationId null; sys_member rows 1. Install answered 200 with seeded {mode:skipped, reason:multi-tenant-no-active-org}. Reseed answered 400 RESEED_SKIPPED and purge 400 RESEED_SKIPPED. The fallback read threw \"Object 'sys_organization_member' not found\".", "A2": "No shared helper or constant exists. The D2 text is an inline template in SecurityPlugin step 3.7 (object and operation parameterized; plugin-security is not a cloud-connection dependency), and plugin-sharing's sharing-rule-service has its own inline spelling. So this file has one local builder, used by all three doors. The seeded report is not spec-published: packages/spec has no install-local response schema. PERMISSION_DENIED is from the standard catalog and needs no ledger row.", "A3": "single: a spy proves resolveActiveOrgId is never called, and install/reseed/purge act with no organizationId. With an active org, all three act in it (unit, plus the door control in org B). RESEED_SKIPPED remains for: no-datasets, objectql-or-metadata-missing, seed-error.", "A4": "Only the clause citing the deleted fallback was reworded. The rule (no membership fallback; no active org means no stamp) is unchanged.", "A5": "ablation-replace.mjs, nested WRAP, two literal anchors. Anchor 1 is the seed refusal line, swapped for the old mode:'skipped' line (blob 5f88579b38e0 to 24f914c847b4). Anchor 2 is the purge 403, swapped for the old RESEED_SKIPPED/400 (to 505004807245). On disk: removed lines 0/0, injected lines 1/1. Unit: 4 red, 33 green. Door: 3 red, 4 green. Restore: three legs prove blob == HEAD 5f88579b38e0 and an empty git diff HEAD. Direction: turned red, as expected." }, "tests": "Head 0590b46d38. pnpm --filter @objectstack/cloud-connection test: 38 files, 466 passed. Typecheck green for cloud-connection, dogfood and service-storage; --listFiles includes both new test files. Door pin install-local-no-active-organization.dogfood.test.ts on a real walled boot: 7/7. Full pnpm lint: exit 0.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 0590b46d38 derived 79 commands, and all 79 ran on that head. Green: 78. Red, by design: check-empty-changeset --base origin/main, because this PR corrects pending .changeset/21728-install-local-purge.md (see deviations; a person confirms on the PR). The earlier --ran reconciliation at c030a4589f: 79/79 with exit codes, 0 NOT MEASURED. NOT MEASURED: the CI-only families that take workflow values (check-shard-attestation --shard matrix; check-issue-citations --census). Reason: there is no value outside a CI run. The ledger blind-spot grep for sys_organization_member, multi-tenant-no-active-org and resolveActiveOrgId over packages/spec/liveness/** and *ledger* found zero hits (exit 1). The control leg (RESEED_SKIPPED, same pathspec) found 2 hits (exit 0).", "line_budget": "n/a", "deviations": [ "Bounded in-place fix: .changeset/21728-install-local-purge.md. Its pending clause '400 RESEED_SKIPPED' became false under this PR. The note is unreleased (version PR 617f25f8a4 is an ancestor of 21773's merge d7fff21736; ancestor check exit 0). check-empty-changeset stays red by design, and the seat should add the path to the claim surface.", "scripts/slot-lookup-baseline.json and scripts/query-options-erasure-baseline.json each ratcheted down by one (the deleted fallback carried those sites).", "Merge of origin/main: a no-op. origin/main was still ebfe658c72, 0 commits ahead, so no merge commit was possible.", "A new seeded.mode value 'refused' in the install host response (not a spec schema, not an export, not a code). No new export or error code.", "The door pin is a new dogfood file: the existing purge file's walled block mints its sessions with active organizations." ], "files_changed": [ "packages/cloud-connection/src/marketplace-install-local-plugin.ts", "packages/cloud-connection/src/marketplace-install-local-no-active-organization.test.ts", "packages/cloud-connection/src/marketplace-install-local-purge.test.ts", "packages/services/service-storage/src/storage-service-plugin.ts (comment)", "packages/qa/dogfood/test/install-local-no-active-organization.dogfood.test.ts", ".changeset/21774-install-local-no-active-org.md (patch, cloud-connection: a bug fix in a released package)", ".changeset/21728-install-local-purge.md (one clause)", "scripts/slot-lookup-baseline.json", "scripts/query-options-erasure-baseline.json" ], "mcp_calls": "0", "api_writes": "3, all through the fleet-write relay: pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, #21780); label-write assign (POST /issues/21780/assignees, os-bill); this comment (POST /issues/21774/comments). Plus git pushes, which are not REST writes.", "open_questions": [ { "question": "Confirm the correction to pending .changeset/21728-install-local-purge.md (check-empty-changeset red by design)?", "options": [ "A: keep it, so one release states one answer", "B: revert it, and the release carries two contradictory sentences" ], "recommendation": "A, because the release would otherwise publish a false sentence" } ], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed. resolveActiveOrgId reads only the better-auth session, so a walled API-key caller is refused with the session wording (before: skipped). Not measured further; in the PR Acceptance notes." ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsACCEPT — PR #21780 at
0590b46d38, pending its DELIBERATE CORRECTION confirmationdomain:cliseat (vacant; this is the previous holder's stay-on tail, named in the close-out brief5985827862) ·session_016GiHYRmLSNWTfbX9gVQkpz· read on GitHub 2026-10-05T00:10ZWhat holds (report
5985886480):- A1: reproduced on a real walled boot. Install answered
seeded skipped, reseed and purge answered400 RESEED_SKIPPED, and the fallback threw "not found" and was swallowed. - ADR-0123 D1/D2/D4:
- the fallback is deleted, ⛔ not repaired;
- reseed and purge answer
403 PERMISSION_DENIED, with one sentence built in one place that names the missing active organization; - install's
seededblock is{mode: 'refused', reason}, a host response and not a spec schema.
- A3:
singlenever calls the resolver. With an active organization, the three doors are unchanged.RESEED_SKIPPEDstays for reseed's other declines. - A5: the ablation is red where predicted, and the blob was restored.
- Tests: 466 pass, the door pin passes 7/7, and lint passes. Of the 79 gate commands, 78 pass; the red one is below.
open_questions[0]: A. The one-sentence correction to pending.changeset/21728-install-local-purge.md(itsScope.bullet,400 RESEED_SKIPPED→403 PERMISSION_DENIEDnaming the organization) is kept, so one release states one answer. That path joins this claim's surface by this record.Check Changeset/check-empty-changesetis red by design (a DELIBERATE CORRECTION).- Per
landing-operations.md, a same-head contract review record that names the edited note confirms it.
Deviations:
- two baselines ratcheted down by one each: accepted;
- the
mainmerge was a no-op: accepted; seeded.mode: 'refused': accepted, since it is a host response value and not an export, schema or code;- a new dogfood file: accepted.
Clause-②: nostands.
Generated by Claude Code
- A1: reproduced on a real walled boot. Install answered
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsHandover note: #21774 / PR #21780 is passed to the next
domain:cliseatprevious holder
session_016GiHYRmLSNWTfbX9gVQkpz· 2026-10-05T00:12Z · the maintainer ordered sign-off without a stay-on ⇒ hot handover; the caretaker is the nextdomain:cliseatCurrent state:
- PR fix(cloud-connection): refuse install-local sample data for a session with no active organization (ADR-0123 D2/D4) #21780 at
0590b46d38is a draft, ACCEPTED by the seat (5985901016), with CI running. Check Changesetis red by design, a DELIBERATE CORRECTION. This PR rewrites one sentence of pending.changeset/21728-install-local-purge.md, itsScope.bullet:400 RESEED_SKIPPED→403 PERMISSION_DENIEDnaming the missing active organization. The ACCEPT kept it (open question answered A), and that path is on this claim's surface.
Landing steps the caretaker owns (⛔ the review judgment is already made; do not redo it):
- Once every check run on the head has completed, and the only red is
check-empty-changeset, commission ONE same-head contract review atCONTRACT_REVIEW_TIER(node scripts/pm/record-recognisers.mjs --brief-template). Its record names the edited note and judges the rewritten sentence (landing-operations.md: a same-head PASS confirms a DELIBERATE CORRECTION red, ⛔ no maintainer wait). - On PASS:
- run
check-expected-skips,check-governed-merges --prandgit merge-tree; - relay
pr_readyandautomerge_enable.
- run
- After the merge:
- verify a single-parent squash that is an ancestor of
main; - post the landed note on [finding] install-local: resolveActiveOrgId's "first membership" fallback queries
sys_organization_member, an object nothing defines — a walled session with no active organization is seeded "skipped" though its user holds asys_memberrow #21774 and strippm:dispatched.
- verify a single-parent squash that is an ancestor of
- Any other red on the head is a new review matter for the caretaker. It is not covered by this ACCEPT.
Review criteria already applied: ADR-0123 D1/D2/D4,
Clause-②: no, nopackages/specpath, and theservice-storagechange is a comment only (declared5985378606on #21118).
Generated by Claude Code
- PR fix(cloud-connection): refuse install-local sample data for a session with no active organization (ADR-0123 D2/D4) #21780 at
objectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (takeover of claim
5985374476; hot handover, the dev has finished)
Session:session_01RWZbGvPFcRKvUqASZtunCU
Account:os-warren(the seat's linked user asget_meanswers it; the card's and PR #21780's assignee from this stroke)
Branch:claude/issue-21774-install-local-no-active-org
Worktree: none in this session; the deliverable is PR #21780's head, and this seat writes no code
Domain:domain:cli
Seat:domain:cli#1
File surface: unchanged from claim5985374476, plus.changeset/21728-install-local-purge.md(one clause, joined by ACCEPT5985901016). PR #21780's file list, read 2026-10-05T00:19Z:.changeset/21728-install-local-purge.md·.changeset/21774-install-local-no-active-org.md·packages/cloud-connection/src/marketplace-install-local-no-active-organization.test.ts·packages/cloud-connection/src/marketplace-install-local-plugin.ts·packages/cloud-connection/src/marketplace-install-local-purge.test.ts·packages/qa/dogfood/test/install-local-no-active-organization.dogfood.test.ts·packages/services/service-storage/src/storage-service-plugin.ts(comment only, declared5985378606on #21118) ·scripts/query-options-erasure-baseline.json·scripts/slot-lookup-baseline.json
Container & model:S,mode:subagent,model: default (opus)build, done and unchanged. The same-head review is at the ceilingCONTRACT_REVIEW_TIER, reason:landing-operations.md「DELIBERATE CORRECTION 红(check-empty-changeset):同 head 达档复核 PASS 记录即确认」.dispatch-gates --tierover the nine paths: no path-derived mandate.
Clause-②: no
Thread-read: 5985929630
Serial constraints cleared: open PRs read 2026-10-05T00:20Z (#21763, #21760, #21679, #21352 with both file pages): none touches the nine paths. This file's chain: #21775, then #21776, wait for this PR's merge (fold-or-serial: SERIAL); #21762 stayspm:blockedbehind #21727 (open; PR #21760 in flight indomain:engine).Release: claim
5985374476, sessionsession_016GiHYRmLSNWTfbX9gVQkpz, accountos-bill, passes to this seat. Provenance: who — the maintainer; words — 「前任已下班, 21780 你也接手」; where — the chat of sessionsession_01RWZbGvPFcRKvUqASZtunCU, after the previous holder's tail note5985942434on seat post #6024. The previous holder named this hot handover itself (handover note5985929630).Handover record: last pushed sha
0590b46d38d5e942324b59a1f3361c98b9978683(PR #21780, draft). ACCEPTED5985901016. CI on that head at 2026-10-05T00:21Z: 26 success · 3 skipped · 3 in progress · 1 failure,Check Changeset, the DELIBERATE CORRECTION by design. Next: one same-head review atCONTRACT_REVIEW_TIERnaming.changeset/21728-install-local-purge.md; on PASS,check-expected-skips,check-governed-merges --pr 21780,git merge-tree, then the relay'spr_ready+automerge_enable.domain:cliseat ·session_01RWZbGvPFcRKvUqASZtunCU· 2026-10-05T00:55Zobjectstack-fleet commented
on Oct 5, 2026 ContributorAuthorMore actionsLanded: PR #21780 →
e09f1aca00, a single-parent queue squashdomain:cliseat ·session_01RWZbGvPFcRKvUqASZtunCU· 2026-10-05T01:35Z- Landing shape:
git rev-list --parents -n 1 e09f1aca00names one parent (e83c9f6154);e09f1aca00is an ancestor oforigin/main, and the pre-merge head0590b46d38is not. Merged 2026-10-05T01:34:15Z through the merge queue (added_to_merge_queue2026-10-05T01:01:40Z). - Content reading on
origin/main:marketplace-install-local-plugin.tscarriesnoActiveOrganizationRefusal(6 hits) and nosys_organization_member(0; same file, same instrument, a hit on the builder above is its control);.changeset/21774-install-local-no-active-org.mdis present;.changeset/21728-install-local-purge.mdline 11 reads403 PERMISSION_DENIED, the DELIBERATE CORRECTION as reviewed.
- Review of record: contract review PASS
5986316914on that head (independent agent atCONTRACT_REVIEW_TIER, adopted by this seat), which named the corrected note and judged its sentence. TheCheck Changesetred rode into the queue under its workflow's own text (pull_requestonly, not a required context). - Closure: closed
completedby the PR's oneFixes #21774line. The lane's open set went 11 → 10, and [finding] install-local: resolveActiveOrgId's "first membership" fallback queriessys_organization_member, an object nothing defines — a walled session with no active organization is seeded "skipped" though its user holds asys_memberrow #21774 is the only card that left it. - Hold released:
marketplace-install-local-plugin.tsis free. Its serial chain continues: [finding] marketplace install-local installs a manifest whose engines.protocol this runtime cannot satisfy (^16 on 17): 200 success, while POST /api/v1/packages refuses it 422 OS_PROTOCOL_INCOMPATIBLE #21762 (p2, unlocked by triage5986276908), then [finding] install-local: the listing'swithSampleDatais install-wide, so after a purge in organization A,GET /install-localread as organization B answerswithSampleData: falsewhile B still holds its 28 seed rows #21775 and [finding] install-local: reseed-sample-data over intact sample rows answers 422 RESEED_NO_ROWS "The package declares no seedable records for this runtime" while the package declares 28 records (all already present) #21776 (p3). - Carried, not filed: the dev's out-of-scope note (a walled API-key caller is refused with the session wording) has
carrier: noneand stays in the PR's Acceptance notes; the review answered it as not a blocker.
- Landing shape:
- added a commit that references this issue
on Oct 7, 2026
Filing gate: ① a product defect with reach measured (class a).
POST /api/v1/marketplace/install-localunder an organization wall (a posture-only boot), by a session with noactiveOrganizationIdwhose user holds asys_memberrow. It answers200withseeded {mode: "skipped", reason: "multi-tenant-no-active-org"}.5983877010):activeOrganizationIdwas null;sys_memberheld 1 row for the admin;Filed by the
domain:cliseat (seat post #6024,session_016GiHYRmLSNWTfbX9gVQkpz). ⛔ Not a claim. Triage sets the grade and the lane.Mechanism (read on
main025008ae95)resolveActiveOrgIdinpackages/cloud-connection/src/marketplace-install-local-plugin.ts(about:2165–:2190) documents a fallback to "the user's first org membership". It runsql.find('sys_organization_member', { where: { user_id } , … }).sys_organization_memberis defined inpackages/**/src. The membership object issys_member, whichpackages/core/src/security/resolve-authz-context.tsreads.tryswallows it, and the fallback never fires.packages/services/service-storage/src/storage-service-plugin.ts:996cites the same object name in a comment.Reader who acts
Triage grades it and decides the fallback's shape: read
sys_member, or drop the fallback and refuse with the active-organization prescription. The resolver's own docblock says it is a SCOPING read, not an authorization one. Related, and distinct: #20477 (the/packagesdomain reading the raw session claim).Dedupe: MCP
search_issues, repo-scoped: 「install-local active organization fallback sys_organization_member resolveActiveOrgId multi-tenant-no-active-org」 gives 24 hits. The nearest are #20477, #20515 and #17010, none of them this. A repo-widegit grep sys_organization_memberfinds this call site and one comment.Generated by Claude Code