You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Generated view — not a second tracker. Authority lives on each card (one-board rule); this body is refreshed by the triage-seat Routine each round from a label query (needs-user-decision, all repos in scope) + literal-text extraction of each card's os-decision-facets block. Edit history = archive. Batch adjudication: reply in ONE comment below with one pair per line, each pair spelled like #9807 B (card number, space, option letter); the triage seat transcribes each ruling back onto its card citing your comment as provenance. (Standing per the 2026-08-18 ruling: standard block, pinned digest, batch channel — 「同意」.)
Last refresh: 2026-08-19 ~11:2xZ, session session_015BAKXkmpGhLRSys9AjNZMX. Current inbox: objectstack 7 (+#9968, +#9952 new this round; +#9617 re-entered by the skills seat — see its provenance note), objectui 1, objectos 5. Total 13. Cards with open downstream dependents: objectos#68 (← objectos#135, and via the chain objectos#75).
objectstack #9968 — impersonate_user / set_user_role still 403 every platform admin; neither vendor route is safely raw-mountable (auth/session boundary + ADR-0068 Option-3 veto tension)
Recommendation: B (retire set_user_role; for impersonate_user, measure the plugin-endpoint override question first, then re-implement as a better-auth plugin endpoint or retire) · A = status quo (dead buttons, fails closed) · C = re-implement set-role with a vendor-excluding vocabulary + plugin-endpoint impersonate.
measured business pull: Both buttons are measured broken today (byte-identical 403 for admin and plain member). But nothing measured pulls for set-role's only effect — writing the vetoed scalar; impersonation is a real admin-support workflow, though no usage telemetry exists.
startup scope discipline: Remove beats declare-and-maintain for set-role. For impersonate, the cheap first step is the unmeasured probe (checkEndpointConflicts override behaviour), not a commitment to re-implement.
Confidence gap: this analysis cannot see whether any real deployment relies on impersonation (zero usage telemetry), and the plugin-endpoint conflict behaviour on better-auth 1.7.1 is explicitly unmeasured — if the probe fails, the impersonate half of B collapses back into A vs. a much more expensive path.
objectstack #9952 — [field report] rc→GA envs: package-declared permission sets frozen at first-boot snapshot; provenance skip is silent, no adoption/migration path (stored-data migration shape)
Recommendation: B (explicit operator command, e.g. os meta adopt-permission-sets, + surface the skip in Setup) · A = boot-time auto-adoption + surfacing · C = document SQL remediation only.
<!-- os-decision-facets -->
platform long-term coherence: The env-authored protection is sound; the defect is the platform's own historical rows landing in that bucket with no exit. A one-time adoption path restores the [cli/plugin-security] dev 元数据物化不一致:默认权限集 insert-if-not-exists 不重物化(声明集走 upsert) #2705 reconcile intent without weakening provenance; leaving it means "declared = enforced" is permanently false for every rc→GA env.
measured business pull: Production field report, measured on a live env — grants shipped after first boot return 403 to real users, remediation today is raw SQL. Every env upgraded along the same rc line is affected.
AI-agent error-resistance: The current failure signal is a log counter — the exact silent-tolerance shape that lets drift run for weeks. Surfacing the skip loudly (Setup badge/warning on the set) is the contract-tightening half and looks safe under every option.
startup scope discipline: Keep it a narrow, one-time adoption keyed on name-match + provenance-predates-scheme; do not build a general reconciliation framework.
Confidence gap: cannot see how many envs sit on the rc→GA line, nor whether any genuinely admin-authored set shares a package set's name in the wild — the collision likelihood is what would flip B to A.
Recommendation: A (three-step retirement: measure population → boot-sweep migration into headers_secret → flip readLegacyHeaders to loud rejection; migration isolated in its own flagged PR) · B = migrate but keep warn-and-accept · C = leave as-is.
startup scope discipline: the work is a bounded three-step retirement with an in-package precedent (migrate-webhook-secrets.ts); the alternative — keeping the legacy path forever — is an open-ended maintenance obligation.
Confidence gap: deployed-instance population of pre-[security] webhook custom headers are still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 legacy rows unmeasured; if large, the migration's blast radius and idempotency proof deserve extra scrutiny before A executes.
objectstack #9901 — federation datasource routes admit any authenticated caller while the admin twin now requires a capability (security boundary; two WRITE routes included)
Recommendation: A (manage_platform_settings on the read twins per #9593; manage_metadata on the write routes import/refresh-catalog; fold the equivalence-test divergence row back) · B = mirror #9593 exactly, no read/write split · C = rule the federation family deliberately lower-privilege and document it.
measured business pull: the asymmetry is measured and pinned in remote-tables-twin.equivalence.test.ts; no user has asked for a lower-privilege introspection door — but datasources.external.* IS published SDK surface, so a new capability requirement is a behaviour change for any real caller presenting a plain credential.
AI-agent error-resistance: one admission policy for one operation family is the shape agents can't get wrong; two doors with different gates invite the "use the other spelling" bypass an agent will find.
startup scope discipline: the fix reuses an existing seam (resolveExecutionContext + systemPermissions, already read by package-routes.ts) — no new mechanism; the decision cost is the SDK-caller break, not the code.
Confidence gap: real-world datasources.external.* SDK callers invisible from the repo — A and B both break a non-admin production caller if one exists, and no staged-migration story has been designed.
objectstack #9885 — sys_position.permissions is a declared "JSON-serialized array of permission strings" column with zero producers and zero readers (enforce-or-remove)
Recommendation: A (REMOVE via the ADR-0049/ADR-0087 retirement flow, incl. the clone_position copy entry and docs riders; objectui designer-preview check folded into the retirement checklist) · B = enforce (design position-level direct grants — a real security feature, only on real pull) · C = leave declared-and-inert.
measured business pull: zero — 97 sys_position-naming files read; no producer, no reader; the only in-file reference is clone_position copying a value nothing writes. Nobody is using it.
AI-agent error-resistance: the declared textarea tells an AI author "grant permission strings directly on a position" — a capability the runtime does not have; an agent following the declaration authors security config that silently does nothing. Removal makes the wrong model unwritable.
startup scope discipline: implementing position-level direct grants (the enforce arm) is a whole security feature with no pull; remove wins by default under the standing enforce-or-remove posture.
Confidence gap: objectui not searched (evidenceScope: framework repo only) — a console position-designer consumer would need a rider; hand-filled deployment data invisible.
Recommendation: A (converge on refuse-loudly in both kernels + an explicit supersede spelling for #9863's config-over-CLI case, pinned dual-kernel) · B = converge on overwrite-with-warning · C = declare the kernels intentionally different and document it.
AI-agent error-resistance: loud refusal on duplicate names + an explicit override/supersede API is the shape an agent cannot misuse; silent last-writer-wins is exactly the tolerance that hides authored mistakes.
objectstack #9617 — checklist-test's documented QA-run title convention matches 0 of 23 real records (governed-surface contract; ⚠️ has a recorded ruling AND a revert — see provenance)
Recommendation: 2, new-records-only (one canonical title shape, strict parser, no migration of the 23 records) · 1 = document bends to measured reality. Provenance: comment 5334893052 (08-18 22:31) recorded Option 2 as ruled via the live-chat batch acceptance 「其他接受你的建议」; the skills seat (comment 5340733624, 08-19 10:19) re-entered it for an explicit per-card verdict. A one-word confirm resolves it.
<!-- os-decision-facets -->
platform long-term coherence: a documented convention matching 0 of 23 real records is declared≠enforced in the agent-instruction layer; only direction 2 (one canonical shape, strict parser) prevents recurrence.
AI-agent error-resistance: one emitted shape + a strict parser that prints what it cannot read makes deviation loud on first occurrence; canonizing five phrasings is the tolerant-consumer shape that hides authoring errors.
startup scope discipline: direction 2 with new-records-only costs one SKILL.md edit and zero migration; the "Not parsed" roll-up section already exists as the enforcement surface.
Confidence gap: none material on substance — the open question is provenance, above.
objectui #5301 — WidgetConfigPanel's resolveLabel reads only the RETIRED label form; opening the panel on a locale-map title shows EMPTY and a save writes '' over the author's map
Recommendation: A (display via pickLocalized; un-edited fields round-trip byte-for-byte; an edit writes the active locale's map entry, preserving other locales; map-editing UX stays a future card) · B = read fix + lossy collapse-to-string on edit · C = full multi-locale editing UI now.
measured business pull: the destructive path is the ordinary one — open a widget whose title is an inline locale map, change anything, save ⇒ the author's map is replaced by ''. Studio authors hit this on every map-titled widget today.
AI-agent error-resistance: an editor that silently collapses a multi-locale map to one string (or to empty) destroys data with no failure signal; write-back-only-the-edited-locale keeps saves idempotent for untouched fields.
startup scope discipline: a full map-editing UI is the expensive road; the minimal honest fix needs no new UI.
Confidence gap: not checked whether the dashboard save path round-trips unknown keys untouched or rebuilds config from the draft — decides whether A needs a diff mechanism.
objectos inbox (5 open — options and recommendations on the cards; standard facet blocks pending backfill, a low-frequency sub-round item)
objectos Fix test data to match evolved schemas #137 — root engines.node >=22 claims a window (22.0.0–22.11.x) yargs does not support. Card recommendation: 2+1 (strengthen the gate to "declared floor satisfies every dependency range" + tighten the declaration to >=22.12.0).
objectos 🔗 Broken links detected in documentation #138 — fourth Node floor declaration: tools/ci-scripts says >=20.0.0 while the repo says 22. Fork: one repo-wide floor vs. accurate per-package floors; either way is a one-line follow-up.
Generated view — not a second tracker. Authority lives on each card (one-board rule); this body is refreshed by the triage-seat Routine each round from a label query (
needs-user-decision, all repos in scope) + literal-text extraction of each card'sos-decision-facetsblock. Edit history = archive. Batch adjudication: reply in ONE comment below with one pair per line, each pair spelled like#9807 B(card number, space, option letter); the triage seat transcribes each ruling back onto its card citing your comment as provenance. (Standing per the 2026-08-18 ruling: standard block, pinned digest, batch channel — 「同意」.)Last refresh: 2026-08-19 ~11:2xZ, session
session_015BAKXkmpGhLRSys9AjNZMX. Current inbox: objectstack 7 (+#9968, +#9952 new this round; +#9617 re-entered by the skills seat — see its provenance note), objectui 1, objectos 5. Total 13. Cards with open downstream dependents: objectos#68 (← objectos#135, and via the chain objectos#75).objectstack #9968 —
impersonate_user/set_user_rolestill 403 every platform admin; neither vendor route is safely raw-mountable (auth/session boundary + ADR-0068 Option-3 veto tension)Recommendation: B (retire
set_user_role; forimpersonate_user, measure the plugin-endpoint override question first, then re-implement as a better-auth plugin endpoint or retire) · A = status quo (dead buttons, fails closed) · C = re-implement set-role with a vendor-excluding vocabulary + plugin-endpoint impersonate.<!-- os-decision-facets -->
set_user_role(B) shrinks the retired dual-identity surface — ADR-0068 moved platform-admin membership tosys_user_permission_set, and a supported UI writer for the legacy scalar re-grows exactly that contract. For impersonation, a better-auth plugin endpoint (not a raw Hono mount) is the only shape that keeps the signed-cookie contract with/admin/stop-impersonatingand the better-auth bearer plugin lets a bearer session silently shadow an impersonation the server just created — /admin/impersonate-user returns 200 and is a no-op for any bearer client #8243 rotation hook attached.checkEndpointConflictsoverride behaviour), not a commitment to re-implement.Confidence gap: this analysis cannot see whether any real deployment relies on impersonation (zero usage telemetry), and the plugin-endpoint conflict behaviour on better-auth 1.7.1 is explicitly unmeasured — if the probe fails, the impersonate half of B collapses back into A vs. a much more expensive path.
objectstack #9952 — [field report] rc→GA envs: package-declared permission sets frozen at first-boot snapshot; provenance skip is silent, no adoption/migration path (stored-data migration shape)
Recommendation: B (explicit operator command, e.g.
os meta adopt-permission-sets, + surface the skip in Setup) · A = boot-time auto-adoption + surfacing · C = document SQL remediation only.<!-- os-decision-facets -->
Confidence gap: cannot see how many envs sit on the rc→GA line, nor whether any genuinely admin-authored set shares a package set's name in the wild — the collision likelihood is what would flip B to A.
objectstack #9930 — retire the legacy
sys_webhook.definition_json.headerscleartext read path (stored-data migration + accepted-input removal)Recommendation: A (three-step retirement: measure population → boot-sweep migration into
headers_secret→ flipreadLegacyHeadersto loud rejection; migration isolated in its own flagged PR) · B = migrate but keep warn-and-accept · C = leave as-is.<!-- os-decision-facets -->
headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 — one storage location for webhook headers instead of a permanent legacy fork; shrinks a special case.sys_webhookstill declares noenableblock — the read-surface narrowing #7799 and #7986 both pointed at was never delivered, and #7986 closedcompleted#9756's reachable-cleartext concern (theenable.apiMethodsremedy measured as a no-op;urlmasking ruled won't-fix in [security] decide explicitly: a webhook URL can BE the credential (Slack/Discord-style endpoints), and it is stored plain on two objects #8025). No user asked for legacy rows to keep working silently.content/docs/automation/webhooks.mdxstill documents custom headers as living insys_webhook.definition_json, and omitsheaders_secretentirely — the doc points authors at the cleartext column #7986 moved them out of #9928 fixes the docs, a loud dated rejection (post-migration) makes writing headers intodefinition_jsonimpossible to get silently wrong.migrate-webhook-secrets.ts); the alternative — keeping the legacy path forever — is an open-ended maintenance obligation.Confidence gap: deployed-instance population of pre-[security] webhook custom
headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 legacy rows unmeasured; if large, the migration's blast radius and idempotency proof deserve extra scrutiny before A executes.objectstack #9901 — federation datasource routes admit any authenticated caller while the admin twin now requires a capability (security boundary; two WRITE routes included)
Recommendation: A (
manage_platform_settingson the read twins per #9593;manage_metadataon the write routesimport/refresh-catalog; fold the equivalence-test divergence row back) · B = mirror #9593 exactly, no read/write split · C = rule the federation family deliberately lower-privilege and document it.<!-- os-decision-facets -->
listRemoteTablesroute twins diverge on?schema=— the admin spelling drops it #7955 request shape, finding: the external-datasource federation HTTP family mounts outside the enforceAuth seam with no guard of its own — read and write #9686 anonymous axis); the capability axis is the first pinned disagreement — converging shrinks a special case, and the write routes (import,refresh-catalog) creating live metadata behind auth-only is the sharpest edge.remote-tables-twin.equivalence.test.ts; no user has asked for a lower-privilege introspection door — butdatasources.external.*IS published SDK surface, so a new capability requirement is a behaviour change for any real caller presenting a plain credential.resolveExecutionContext+systemPermissions, already read bypackage-routes.ts) — no new mechanism; the decision cost is the SDK-caller break, not the code.Confidence gap: real-world
datasources.external.*SDK callers invisible from the repo — A and B both break a non-admin production caller if one exists, and no staged-migration story has been designed.objectstack #9885 —
sys_position.permissionsis a declared "JSON-serialized array of permission strings" column with zero producers and zero readers (enforce-or-remove)Recommendation: A (REMOVE via the ADR-0049/ADR-0087 retirement flow, incl. the
clone_positioncopy entry and docs riders; objectui designer-preview check folded into the retirement checklist) · B = enforce (design position-level direct grants — a real security feature, only on real pull) · C = leave declared-and-inert.<!-- os-decision-facets -->
sys_position_permission_set); a parallel free-textpermissionscatalogue on Position is a second, never-implemented grant vocabulary — removing it shrinks the security model to the one real path. Same class as the ruled [finding]sys_user_permission_set.delegated_fromis declared and data-door-writable, but the runtime delegation gate structurally never reads it on this object #9730 (delegated_from, REMOVE 2026-08-18) andsys_permission_set.activeandsys_position.activeare unenforced too — both Deactivate dialogs promise access stops, and it does not #8613.sys_position-naming files read; no producer, no reader; the only in-file reference isclone_positioncopying a value nothing writes. Nobody is using it.Confidence gap:
objectuinot searched (evidenceScope: framework repo only) — a console position-designer consumer would need a rider; hand-filled deployment data invisible.objectstack #9864 — duplicate plugin registration: LiteKernel throws, ObjectKernel silently overwrites (fourth two-kernel semantic split; #9863 rides the overwrite)
Recommendation: A (converge on refuse-loudly in both kernels + an explicit supersede spelling for #9863's config-over-CLI case, pinned dual-kernel) · B = converge on overwrite-with-warning · C = declare the kernels intentionally different and document it.
<!-- os-decision-facets -->
os serveboot path — the CLI registersAuditPluginwith no options #9863's config-supersedes-CLI path); nobody has asked for silent replacement semantics, and the failure direction (a differently-configured instance silently replacing a plugin, logging "registered" twice) is the expensive one.has()check + an explicit registration option); option B (document divergence) creates a permanent two-contract obligation.Confidence gap: no census of real boot paths relying on the overwrite (only finding: record-view auditing has no configuration path on the
os serveboot path — the CLI registersAuditPluginwith no options #9863's collision is measured); A needs that census first or quiet boots become hard failures.objectstack #9617 — checklist-test's documented QA-run title convention matches 0 of 23 real records (governed-surface contract;⚠️ has a recorded ruling AND a revert — see provenance)
Recommendation: 2, new-records-only (one canonical title shape, strict parser, no migration of the 23 records) · 1 = document bends to measured reality. Provenance: comment
5334893052(08-18 22:31) recorded Option 2 as ruled via the live-chat batch acceptance 「其他接受你的建议」; the skills seat (comment5340733624, 08-19 10:19) re-entered it for an explicit per-card verdict. A one-word confirm resolves it.<!-- os-decision-facets -->
Confidence gap: none material on substance — the open question is provenance, above.
objectui #5301 — WidgetConfigPanel's
resolveLabelreads only the RETIRED label form; opening the panel on a locale-map title shows EMPTY and a save writes''over the author's mapRecommendation: A (display via
pickLocalized; un-edited fields round-trip byte-for-byte; an edit writes the active locale's map entry, preserving other locales; map-editing UX stays a future card) · B = read fix + lossy collapse-to-string on edit · C = full multi-locale editing UI now.<!-- os-decision-facets -->
mcponly when it is actually serveable #4032 swept three); whichever write-back rule is chosen should be stated once and shared, not re-derived per panel.''. Studio authors hit this on every map-titled widget today.Confidence gap: not checked whether the dashboard save path round-trips unknown keys untouched or rebuilds config from the draft — decides whether A needs a diff mechanism.
objectos inbox (5 open — options and recommendations on the cards; standard facet blocks pending backfill, a low-frequency sub-round item)
engines.node >=22claims a window (22.0.0–22.11.x) yargs does not support. Card recommendation: 2+1 (strengthen the gate to "declared floor satisfies every dependency range" + tighten the declaration to>=22.12.0).tools/ci-scriptssays>=20.0.0while the repo says 22. Fork: one repo-wide floor vs. accurate per-package floors; either way is a one-line follow-up.Studiois a third surface name the 🔗 Broken links detected in documentation #79 naming decision does not cover.TRANSLATION_BOT_LOGINis set (also blocks objectos#135 and, via the unlock chain, objectos#75).