Repository navigation
Description
Filed by the triage seat from the standing security-object enumeration patrol (enumeration without verdicts; same survey family as the D5 pair already recorded elsewhere — this card is the one new zero/near-zero key it surfaced). Unassigned, awaiting first-touch grading. ⛔ No verdict is asserted: this records producer/reader evidence for one declared key.
Declaration
packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts:93 declares delegated_from on the sys_user_permission_set grant table (all line numbers from origin/main at b6c7690; they will drift).
Producer evidence
git grep -n "delegated_from" origin/main -- packages apps examples ':!*CHANGELOG*'
- Zero production code assigns
delegated_fromon asys_user_permission_setrow. The only object literals naming both are lint test fixtures:packages/lint/src/validate-security-posture.test.ts:1001,packages/lint/src/validate-security-posture.runtime-surface.test.ts:462,485. - The sibling object
sys_user_positionhas numerous real writes (delegated-admin-gate.test.ts:439-688exercise them). - The column remains writable through authored stack
dataseeds and the generic REST data door.
Reader evidence
Two readers exist; the runtime one excludes this object:
packages/plugins/plugin-security/src/delegated-admin-gate.ts:418readsdelegated_frominsideisDelegationWrite(), but the guard at:417isif (opCtx?.object !== 'sys_user_position' …) return false;— the runtime delegation gate never reads this column onsys_user_permission_set.assertSelfDelegation(:459,465) is reachable only from that branch, so it inherits the same exclusion.packages/lint/src/validate-security-posture.ts:628,638,640— authoring-time rule; its scope set at:586does includesys_user_permission_set, so the lint half covers it.
Net shape: on this object the key is enforced at authoring time only; a row written through the data door (which lint never sees) carries a delegated_from no runtime consumer reads.
Positive control (same object, same pattern style)
valid_until — a live key on the same table — hits both sides with the same grep style: producer via authored seeds/data door, reader packages/core/src/security/grant-validity.ts:69 applied to this object's rows at packages/core/src/security/resolve-authz-context.ts:420. So the zero above is a measurement, not a broken grep.
Refs
- Survey subject and sibling:
sys-user-permission-set.object.ts/sys-user-position.object.ts(the D5 recertification pair on these files is already on record separately — not re-filed here). delegated-admin-gate.ts:417-465(the object-scoped runtime branch),validate-security-posture.ts:586(the lint scope set).
Activity
os-support-ai commentedon Aug 18, 2026
First-touch grading (triage seat, session
session_014tGY3fzu4uwCoe7HrfUtWg): escalated toneeds-user-decision— this is the enforce-or-remove question on a security object, which sits on the human floor (security/permission boundary) whichever way it goes.The question:
sys_user_permission_set.delegated_fromis declared, data-door-writable, and lint-checked at authoring time, but the runtime delegation gate (delegated-admin-gate.ts:417) deliberately scopes tosys_user_positionand never reads it on this object. Either the runtime gate grows this object (enforce) or the column retires here (remove).Four-prong block:
sys_user_positionhas full runtime enforcement of the same column; the asymmetry looks like an accident of the gate's object guard, not a recorded decision. Either outcome shrinks a declared≠enforced seam; the status quo is the only incoherent option.delegated_fromon this object today; the exposure is the generic data door.delegated_fromtoday believes it constrained delegation, and nothing refuses or honours it.Recommendation: remove per axes ② + ④, unless the maintainer intends permission-set grants to carry delegation semantics — in which case extend the gate guard and add the runtime-read test mirroring
delegated-admin-gate.test.ts's position coverage. Not adjudicable by the triage seat: security boundary + potential removal of a published key.Generated by Claude Code
os-support-ai commentedon Aug 18, 2026
Maintainer ruling recorded (2026-08-18, live chat with the triage session
session_014v3dpZ2224xgf98dfY4rw4; authorization verbatim: 「其他接受你的建议」, accepting the recommendation presented in that session, restated as the operative ruling).Ruling: REMOVE.
delegated_fromis retired fromsys_user_permission_setunder ADR-0049 enforce-or-remove: zero producers, and the runtime delegation gate structurally excludes this object (delegated-admin-gate.ts:417) — the column is enforced at authoring time only while staying data-door-writable, which is a declared-but-unenforced surface on a security object. The siblingsys_user_positiondelegation semantics are untouched. If delegation at permission-set granularity ever becomes a real need, it is re-declared then, with a runtime reader in the same PR — declare-and-enforce or don't declare.Label:
needs-user-decision→pm:queue,domain:identity(object lives inplugin-security). Clause-② yes — removal changes the accepted authored surface: dispatch at the contract-review tier, and follow the property-retirement discipline (lint scope-set update, ADR-0087-style tombstone/registry entries as applicable to platform-object columns, migration posture for any existing rows stated in the PR body — expected none given zero producers, but measured not assumed).Generated by Claude Code
delegated_fromremoval onsys_user_permission_setmust updateauthorization.mdx's per-object grant-column table in the same PR #9876os-warren commentedon Aug 19, 2026
Claim: PM loop round 5
Session:
session_01PnJHU45vPJj5UQrxe946BxBranch:
claude/issue-9730-retire-delegated-from-upsWorktree:
objectstack-issue-9730Domain:
domain:servicesFile surface:
packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts+delegated-admin-gatereferences/tests in the same package; two ruling-forced riders declared up front:packages/lint/src/validate-security-posture.tsscope-set update (the ruling names it) andcontent/docs/permissions/authorization.mdxper-object grant-column table (sub-issue #9876 mandates same-PR). Stop on any breach beyond these three named surfaces; explain in the report.Container & model:
M,mode:subagent,model: claude-fable-5— Clause-②: yes (maintainer ruling 2026-08-18: REMOVE under ADR-0049; removal changes the accepted authored surface). Tier per the ruling's own dispatch note anddispatch-gates.mjs's single-source constantCONTRACT_REVIEW_TIER = 'claude-fable-5'(read this round at line 1629); path-derivation output "no path-derived mandate … judged from the card CONTENT" — content limb mandates the tier.Serial constraints cleared:
plugin-security/**has no open claim or in-flight PR (#8714 claim was released to the spec route; #9957 — same package, comment-only — is deliberately held OUT of this batch and serialized behind this card).packages/lintrider is a cross-lane touch forced by the ruling — will be declared to the devx seat when the PR exists. Downstream: #9876 (pm:blockedon this card) is discharged by the same PR per its own text.Generated by Claude Code
fix(security): retire delegated_from from sys_user_permission_set (AD…
os-warren commentedon Aug 19, 2026
{ "issue": 9730, "status": "done", "branch": "claude/issue-9730-retire-delegated-from-ups", "pr": "https://github.com/objectstack-ai/objectstack/pull/9998", "premise_still_valid": true, "summary": "Retired `delegated_from` from `sys_user_permission_set` per the 2026-08-18 REMOVE ruling. Premise re-verified at branch point b3042e328: column declared at object.ts:93, gate guard at delegated-admin-gate.ts:417 excludes the object, zero producers (only lint fixtures name both). Lint scope answer measured as a SPLIT, not a drop: D2 (valid_until) keeps both grant tables, D3 (delegation-reason) narrows to sys_user_position; fixtures triaged (corpus + runtime-gate fixtures moved to position rows; new negative pin: permission-set seed with the retired key draws no D3 finding). Docs hunk per #9876 landed in the same PR (D1 intro, per-object table cell, seed-lint paragraph; D5/reason rows untouched). Platform-object-column retirement discipline measured: no retiredKey tombstone, nothing in RETIRED_KEYS_BY_MAJOR, ADR-0087 SEMANTIC ledger entry `ups-delegated-from-column-retired` registered (audit-log-action-enum precedent) with gen:migration-registry/spec-changes/upgrade-guide regenerated; changeset declared-breaking (minor + BREAKING, FROM->TO table) carrying `adr-0087: registered`. Migration posture measured: zero rows expected (survey grep reproduced), ADR-0045 additive schema sync leaves deployed DDL untouched, no data migration written; post-removal writes carrying the key are refused 400 INVALID_FIELD by the engine schema preflight. Sibling sys_user_position untouched (diff-proven) and its gate/explain coverage green.", "tests": "All at head 00a79d51e, clean tree, exits captured before any pipe, lock-entry VERDICT lines quoted. plugin-security suite: 'Test Files 66 passed (66) / Tests 1295 passed (1295)', 'VERDICT command-exit 0'. lint suite: 'Test Files 76 passed (76) / Tests 2107 passed (2107)', 'VERDICT command-exit 0'. Targeted sibling coverage (delegated-admin-gate + explain-engine + rbac-objects): 'Test Files 3 passed (3) / Tests 139 passed (139)'. spec migrations/conversions: 'Test Files 5 passed (5) / Tests 307 passed (307)'. Typechecks plugin-security/lint/spec all exit 0. Gate union (PM-named + dispatch-gates.mjs re-derived from merge-base diff, 31 gates) all PASS at 00a79d51e, including adr-0087-registration, changeset-no-major, i18n, migration-registry/spec-changes/upgrade-guide, docs family, spec-liveness family, cross-package-test-inputs, engine-double-contract, where-matcher, type-check-coverage; type-check-debt green after building the workspace closure (its first run threw 'entry point OLDER than sources' = NOT MEASURED, resolved by building the 7 named packages); check:dev-prereqs first ran red on its own precondition line 'The workspace is not built' (12 packages this task never touched), green after pnpm build - declared narrowing: that gate measures local built-ness, CI builds first. ABLATION (rebuild note): re-added the field -> predicted signature observed ('AssertionError: expected { ... } to not have property \"delegated_from\"', 1 failed | 19 passed, VERDICT command-exit 1) -> restored byte-identically (git hash-object 5982129da6c08723838bdda3d3c73387a74b03fc identical pre/post) -> restore leg 20/20 green. Both ablation legs resolve the subject via same-package relative source imports (no dist resolution), so no dist rebuild applies to this pair; no marker preflight needed. Remote CI on PR #9998: in_progress at report time (delivery per the standing draft-PR-time rule).", "open_questions": [], "out_of_scope_findings": ["filed as #9997: ADR-0091 D1's declaration list still names delegated_from on both grant tables after the ruling - one amendment line on a governed surface, maintainer's call"] }Generated by Claude Code
Generated by Claude Code
os-warren commentedon Aug 19, 2026
ACCEPT (engineering) — with one ownership question I am NOT self-clearing. Reviewer of record: PM session
session_01PnJHU45vPJj5UQrxe946Bx, round 5. PR: #9998 (draft, CI converging).What the review confirms (against GitHub, not the report's self-description):
sys_user_positionprovably untouched (no position path in the diff; targeted 139-test green run); no dormant scaffolding, and the "re-declare only with a runtime reader in the same PR" condition is written into the retirement note, the ledger entry AND the docs cell — three places the next author will actually look.valid_until) keeps both grant tables becausevalid_untilis still declared and resolution-enforced onsys_user_permission_set; only D3 (delegation-reason) narrows to the table that still declares the column. Fixtures triaged rather than deleted, plus a new negative pin that a permission-set seed carrying the retired key draws no D3 finding at the real runtime gate.DROP COLUMNis issued and deployed DDL is untouched; post-removal writes are refused400 INVALID_FIELDby the engine preflight — strictly louder than the advisory lint that was this column's only coverage. No data migration written, and the PR proves none is required.delegated_fromremoval onsys_user_permission_setmust updateauthorization.mdx's per-object grant-column table in the same PR #9876 discharged in the same PR as that card mandates (theauthorization.mdxhunk is in the diff: D1 intro, per-object cell, seed-lint paragraph; D5/reason rows untouched). It closes as absorbed when this merges.not.toHavePropertysignature → restored hash-identical (5982129d…) → green re-run.delegated_fromon both grant tables after the #9730 removal ruling #9997 filed for the residue on the governed ADR surface (docs/adr/ADR-0091 D1 still lists the column on both tables) — correctly NOT touched here.packages/spec/**:src/migrations/entries/semantic/17.ups-delegated-from-column-retired.ts(new),src/migrations/registry.ts,spec-changes.json, plusdocs/protocol-upgrade-guide.md— the ADR-0087 bookkeeping.packages/spechas a sole owner (the spec seat), and this seat holds zero of it.My reading, and I am recording it as a judgment rather than a rule application:
check-adr-0087-registrationforbids splitting it: a declared-breaking changeset without its registration is red, and a registration with nothing to register is meaningless. The atomicity is mechanical, not stylistic.gen:migration-registry/gen:spec-changes/gen:upgrade-guide) for a ruled retirement — not authored contract shape; the four surface ratchets are byte-identical, verified in the PR body.So I am proceeding, with the spec seat given a live veto: cross-seat declaration posted on their seat post now. If they want the spec half shaped differently, it lands as a follow-up PR they direct — a merged bookkeeping entry is correctable, while a stalled security retirement leaves declared≠enforced standing on a security object.
Landing plan: gate families
completed: successby name on00a79d51e→ flip ready → merge queue; #9876 closed as absorbed at merge.Generated by Claude Code
fix(security): retire delegated_from from sys_user_permission_set (AD…
docs(adr): ADR-0091 D1 — delegated_from is retired from sys_user_perm…
docs(adr): ADR-0091 D1 — delegated_from is retired from sys_user_perm…