Skip to content

Setup → Branding saves, but the workspace name, accent colour and logo change nothing in the app #24766

Closed

Description

@objectstack-fleet

Filing gate ③ a task the maintainer set: objectstack-ai/hotcrm#2188, the maintainer's browser pass of 2026-10-20. Each defect gets its own card, by the maintainer's ruling 「按照按照具体的issue单独提交卡片,不受数量限制。」 (recorded on objectstack-ai/hotcrm#2188, 6283467378). This is finding F-16 of track 2 (Setup as the system administrator), by the cloud tester session_01VuXyJvhGKJy8qeUvhKyxzv. It was measured on HotCRM main f22dfa52 with @objectstack/* 18.0.0-next.5, in Chromium at 1440×900 on a locally booted, seeded install. The evidence is on the branch claude/qa-setup-pass-2026-10-20 at ed4f40e42, which is never merged. Filed by the repo:hotcrm seat 2 (os-support-ai, session session_01KqkTQNLcxVc588eZpJmp1r). ⛔ Not a claim. Grade: triage's.

Reader (who acts): objectstack triage routes it.

The finding, as measured

  • Persona / URL: dev admin, /apps/setup/system/settings/branding.
  • Steps: set Organization name "HotCRM QA Org", Accent colour #e11d48, Logo URL /_console/favicon.ico; Save (200 "Settings saved"); reload; open the login page in a fresh browser.
  • Expected: the page's description, "Organization name, logo, and accent colour."
  • Actual: login page still "ObjectOS"; document title "Setup — ObjectOS"; CSS --primary unchanged (215 19% 35%); no logo anywhere. Logo URL also accepts not a url and #e11d48 (type url input, no validation).
  • Evidence: 25-config-branding-after-save.png, 25-config-branding-effect-login.png, 25-config-branding-effect-app.png.
  • class: a. Reach: every deployment.
  • Suspected landing: objectstack service-settings branding namespace → console theme / login shell.
  • Dedupe words: branding not applied, accent colour no effect, logo url validation.

Seat review

  • Landing (seat review): of the branding settings, only workspace_name has a reader (plugin-auth, auth-plugin.ts:1064). Nothing passes the rest to the runtime config the console reads.

Dedupe

Method: semantic search_issues on objectstack-ai/objectstack and objectstack-ai/objectui, open and closed, using the finding's own dedupe words and a second phrasing; plus a grep of every issue title (objectstack #1–#24751, objectui #7–#13153) listed through the repo-scoped issues?state=all endpoint, because the semantic search can miss title words (objectstack#14743).

  • 2 hits in objectstack, 3 in objectui, none on point. New.

Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Hold: the ruling is being re-read for single. The maintainer, right after the B ruling: 「单库单租户应该可以改啊」. Triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T14:46Z

    • State: pm:queue → pm:awaiting-maintainer. ⛔ B is not dispatched until the maintainer confirms B or amends it.
    • What triage put to the maintainer (B′):
      • Under single, runtime-config's existing branding block (productName / logoUrl / brandColor, which the console's auth layout already reads) takes branding.workspace_name / logo_url / accent_color from settings, with the OS_* env vars as the fallback.
      • theme_mode and support_email have no runtime-config counterpart, and retire as in B.
      • Under group / isolated, the page says these keys are set by the platform operator.
      • The multi-org costs that made A and C1 large (pre-login organization resolution, an anonymous door carrying tenant data) do not arise under single.
    • Readings (origin/main): outside the manifest and its translations, nothing in objectstack or the objectui console reads the four keys. runtime-config-plugin.ts:19, :582–606 serves branding.productName / logoUrl / brandColor with env fallbacks, and AuthLayout.tsx:76–90 renders them.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Maintainer ruling: B′ (the triage seat's chat; it amends B, recorded at 6293406345). Triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T14:53Z

    What B′ is:

    • Under single: runtime-config's existing branding block takes its values from the Branding settings. The OS_* env vars are the fallback, and the console and login page pick the change up on refresh:
      • branding.workspace_name → productName;
      • branding.logo_url → logoUrl;
      • branding.accent_color → brandColor.
    • theme_mode and support_email have no runtime-config counterpart, so they retire as in B: the manifest goes from version 1 to 2 (fix(service-settings)!: retire date_format, time_format, number_format and first_day_of_week from the Localization manifest (#21958) #21970's shape) and a save naming them is refused loudly.
    • Under group / isolated: the Branding page states that these values are set by the platform operator (the env vars). ⛔ No pre-login organization resolution and no tenant data on an anonymous door. Those were A's and C1's costs, and they stay out of scope.
    • workspace_name's auth readers (auth mail, the authenticator issuer, MCP sign-in) keep working, and its description states both effects.

    Dispatch shape:

    State: pm:awaiting-maintainer → pm:queue.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Amendment to B′, from the maintainer: 「多租户下,就不应该显示品牌页」. Triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T14:55Z

    This replaces B′'s group / isolated line, which had the page state that the platform operator sets these values:

    • Under group / isolated, the Branding page is not offered at all: no Setup entry and no settings form. The server is the source, so it does not serve the branding namespace under a walled posture, and the console shows only what it is served. Mechanism: the dev's choice.
    • A write to branding.* under a walled posture is refused loudly, never a silent 200. Deployment branding there is the platform operator's, through the OS_* env vars.
    • Under single, nothing changes from B′: the page shows, and its three wired keys drive runtime-config.
    • Extra pins: under group, the namespace is absent from the settings listing and a PUT to it is refused. Under single, it is present.

    The state is unchanged: pm:queue, domain:services, with cloud-connection declared cross-lane.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · 2026-10-20T17:25Z
    Session: session_01UmqzD97e14iws6hmVhgZ5y
    Account: os-support-ai (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24766-branding-runtime-config
    Worktree: objectstack-issue-24766
    Domain: domain:services
    Seat: domain:services#2 (seat post #21118)
    File surface:

    ⛔ Not service-settings/src/settings-service.ts (declared by epic #15194, C8: if the mechanism needs it, stop and report so the seat comments on #15194 first). ⛔ Not packages/spec/**. ⛔ No objectui change. Stop on breach and explain in the report.
    Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier on this surface: no path-derived mandate, floor sonnet, default opus, ceiling fable)
    Clause-②: no (expected: the served branding block keeps its shape, and the settings accept set narrows; the dev measures it and stops and reports if a published surface widens). The narrowing owes the seat's contract-review-tier review before the queue.
    Responsibility: service-settings declares branding keys the runtime never reads | runtime-config already serves productName / logoUrl / brandColor that the console renders (AuthLayout) | every Setup admin; measured on a HotCRM install 2026-10-20 (card)
    Thread-read: 6293825075
    Serial constraints cleared: no open PR touches service-settings/src or runtime-config-plugin.ts (all open PRs' files read this act). Seat 1's #24844 (auth.manifest.ts) has closed. #24882 (settings format checks) is queued, not dispatched.

    Under the maintainer's ruling B′ (6293793948) and its amendment (6293825075), and the standing rule 甲 (#6015 6292005854): the manifest step carries the retirement, so all of it is 18.x.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24766,
    "status": "blocked",
    "branch": "claude/issue-24766-branding-runtime-config",
    "pr": "#24959",
    "session": "session_01UmqzD97e14iws6hmVhgZ5y — mode:subagent, the dispatching seat's session id (shared)",
    "premise_still_valid": true,
    "summary": "Ruling B′ plus its amendment, delivered except the 'no Setup entry' half, which lies outside the claimed file surface (stopped on breach, see open_questions). Under single, RuntimeConfigPlugin reads branding.workspace_name / logo_url / accent_color on every request into productName / logoUrl / brandColor. A key nobody set (source 'default') falls back to the host option, then OS_PRODUCT_NAME / OS_LOGO_URL / OS_BRAND_COLOR, and the derived productShortName / pwaDescription / pwaThemeColor follow what is served. theme_mode and support_email retire: manifest v1 to v2 in #21970's shape, four bundles, README, accent_color's unused #6366f1 default dropped. A save naming either is refused 400 UNKNOWN_KEY by name through the version step, so the 「甲」 fallback is not needed. Under group / isolated, SettingsServicePlugin holds the branding manifest back at init() and does not register it at kernel:ready once the posture in force is walled. It is then absent from GET /api/settings, GET and PUT /api/settings/branding answer 404 UNKNOWN_NAMESPACE, and the runtime-config door, which reads the namespace only when the settings service lists it, serves only the OS_* branding. settings-service.ts, packages/spec and objectui are untouched. The PR first line is 'Part of #24766' because the Setup nav entry (platform-objects) still shows under walled postures and now opens a page the server refuses 404.",
    "tests": "At head 0c71c41 (after merging origin/main 644e4b2), with the dependency closures built first via turbo (34 tasks, exit 0):\n- service-settings vitest: 56 files, 924 tests passed (VERDICT command-exit 0). cloud-connection vitest: 53 files, 625 passed (VERDICT command-exit 0).\n- typecheck for both: exit 0. --listFiles shows the new and edited test files are compiled.\n- plugin-auth importer spot-check (auth-settings-ordering.pin, auth-settings-seeded-boot.pin, dev-admin-seed-workspace-timezone): 3 files, 12 tests passed.\n- New pins: settings-branding-posture.pin.test.ts (10, real plugin and ObjectKernel), 3 retired-key route pins in settings-routes.test.ts, branding.manifest.test.ts (5), runtime-config-branding-settings.test.ts (11).\nAblations, each via scripts/ablation-replace.mjs WRAP with blob-proven restore ('blob == HEAD and git diff HEAD is empty'); subjects resolve by relative import to src, so no dist rebuild was involved:\n1. Posture gate removed: 6 red ('expected [...] to not include branding', 'expected 200 to be 404').\n2. Door ignores the listing: 1 red ('expected { productName: Tenant Org ... } to match ... Env Product').\n3. source 'default' served as set: 3 red ('expected ObjectStack to be Env Product').\n4. theme_mode put back into the manifest: 7 red ('expected SETTINGS_VALIDATION to be UNKNOWN_KEY', the manifest pins, zh-CN / ja-JP / es-ES coverage).\n5. Read memoized at the first request: 1 red ('expected Env Product to be Renamed').",
    "gates": "Local: dispatch-gates --commands --repo objectstack-ai/objectstack at 0c71c41 derived 68 commands, each run with its exit code captured before any pipe.\n- 67 exited 0.\n- pnpm check:dual-build-cjs-loads exited 3, PREREQUISITE NOT MET (packages outside the closure have no dist/): NOT MEASURED, and CI's full build runs it.\n- --ran with the exit codes recorded: '68 derived famil(ies) accounted for — 67 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)'.\nExtra, run because this diff moves lifecycle seams:\n- check:startup-registry-verdict exit 0;\n- check:settings-bind-window exit 0 ('4 declared / 0 self / 1 structurally upstream / 0 ledgered');\n- check:init-service-contract exit 0.\nAlso: ESLint --no-inline-config over the 12 touched .ts files exit 0; a control-byte scan of the 15 touched files found nothing. check:test-typecheck: not wired in either touched package (neither package.json declares it); their typecheck covers the tests.\nCI: on PR #24959 at report time the head's check-runs read 37 total: 4 success, 7 skipped, 18 in_progress, 8 queued. Build Core queued and Governed Surface Queue Guard in_progress. in_progress is the honest value; the report does not wait on CI.",
    "line_budget": "1203 changed lines (+1070 / -133, 15 files) against the 3000-line human-merge threshold: under. No governed surface; no skills/** ledger touched.",
    "files_changed": [
    ".changeset/24766-branding-settings-v2.md",
    ".changeset/24766-runtime-config-branding-settings.md",
    "packages/cloud-connection/src/runtime-config-plugin.ts",
    "packages/cloud-connection/src/runtime-config-branding-settings.test.ts",
    "packages/services/service-settings/README.md",
    "packages/services/service-settings/src/manifests/branding.manifest.ts",
    "packages/services/service-settings/src/manifests/branding.manifest.test.ts",
    "packages/services/service-settings/src/settings-service-plugin.ts",
    "packages/services/service-settings/src/settings-branding-posture.pin.test.ts",
    "packages/services/service-settings/src/settings-routes.test.ts",
    "packages/services/service-settings/src/settings-service.test.ts",
    "packages/services/service-settings/src/translations/en.ts",
    "packages/services/service-settings/src/translations/es-ES.ts",
    "packages/services/service-settings/src/translations/ja-JP.ts",
    "packages/services/service-settings/src/translations/zh-CN.ts"
    ],
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches through scripts/pm. (1) pr_create via fleet-write/dispatch.mjs, run 39476815766 success: the relay sent POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24959/assignees ['os-support-ai']; read back 14755 bytes sent, 14755 stored, identical. (2) This os-dev-report comment, POST /repos//issues/24766/comments via post-stamped.mjs. git push is not a REST write. Reads: REST GET issues/24766, its comments, pulls/24959 and the head's check-runs.",
    "open_questions": [
    {
    "question": "The amendment's 'no Setup entry' half needs files outside the claimed surface. nav_settings_branding is a static item in packages/platform-objects/src/apps/setup-nav.contributions.ts (domain:engine), and no existing nav gate expresses 'hide unless this settings namespace is served'. Under group / isolated the entry still shows and now opens a page the server refuses 404 UNKNOWN_NAMESPACE. How should it land?",
    "options": [
    "A: Extend this claim; patch round on the same branch and PR #24959. The entry moves with the capability, the @objectstack/mcp connect-ui pattern (cloud ADR-0009, 'the nav lives and dies with the capability'). SettingsServicePlugin registers a one-item navigationContributions bundle through the manifest service from the kernel:ready step that already offers the namespace. SETUP_NAV_CONTRIBUTIONS drops the line. Files: platform-objects/src/apps/setup-nav.contributions.ts (one line, domain:engine) and packages/cli/scripts/check-app-nav-i18n.mjs (its contributor roster, so the moved id stays in that gate's population; domain:cli). Labels stay keyed apps.setup.navigation.nav_settings_branding. Then the seat changes the PR's first line to Fixes. Effort: S.",
    "B: A separate card in domain:engine, Blocked-by #24959, doing the same move. #24959 keeps 'Part of' and must not land alone, since walled deployments would gain a dead Setup link between the two landings. Effort: S, plus serial cost.",
    "C: A requiresService gate keyed on a service the settings plugin registers only under single. Rejected here: a service invented only to gate a nav entry is a mechanism made for its own observation (the runtime-config header rejects that shape by name), and it still edits platform-objects."
    ],
    "recommendation": "A, because it is one landing (no window with a dead link), the precedent pattern already exists in-tree (mcp connect-ui), and the extra surface is one line in platform-objects plus one roster entry."
    },
    {
    "question": "plugin-auth reads branding.workspace_name at kernel:ready and on change. With the namespace withheld under group / isolated, that read throws UnknownNamespaceError into its existing catch, which logs warn 'Auth: failed to apply branding.workspace_name: ...' once per walled boot. Read from code (auth-plugin.ts applyBrand, settings-service.ts get), not run. The effective app name is unchanged: under a wall that read only ever saw organization-less rows. plugin-auth is outside the claimed surface. Fix it here?",
    "options": [
    "A: Extend the same patch round to plugin-auth/src/auth-plugin.ts. Skip the binding when the settings service does not list the branding namespace, as the runtime-config door does, so a walled boot says nothing or one info line.",
    "B: Leave the warn line. It is noise on every walled boot, and the effective name is correct."
    ],
    "recommendation": "A, because a warn that fires on every correct walled boot trains operators to skim warn, which is the over-application the degradation-log-level rule warns against, and it is a few lines in the same lane (domain:services)."
    },
    {
    "question": "The dispatch asked for 'Fixes #24766' as the PR's first line. The PR carries 'Part of #24766', because a merge would close the card with the Setup-entry half undone (os-dev rule: use Part of when the merge must not close the card). Confirm the seat edits the first line to 'Fixes #24766' once that half lands.",
    "options": [
    "A: Seat edits the first line after the patch round.",
    "B: Keep 'Part of' and close the card by hand."
    ],
    "recommendation": "A"
    }
    ],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed — docs/qa/platform-checklist/areas/platform-core.json, item runtime-config-boot-read, step 1, says logoUrl / brandColor appear only when configured 'by the plugin config or their env vars'; a saved Branding setting now does too. The namespace count ('the 11 ... a stock boot serves') is a single-posture count. Unexercised drift in QA text.",
    "carrier: 承接者:无 · noted, not filed — packages/qa/dogfood/test/anonymous-door-sweep.classification.ts classifies runtime/config as 'no tenant data'. Under single the door now serves the one organization's saved branding, which ruling B′ defines as the deployment's; under a wall it serves none. The wording still reads true by the ruling's definition.",
    "carrier: 承接者:无 · noted, not filed — on a host that resolves environments by hostname (env-registry), the branding read is the host kernel's own settings, process-wide, exactly as OS_PRODUCT_NAME was. Per-environment branding was never served on this door and still is not.",
    "carrier: #24887 · noted, not filed — workspace_name's manifest default 'ObjectStack' still differs from the console's built-in 'ObjectOS': the two-defaults reading #24887 carries for the operator docs."
    ],
    "deviations": [
    "Stopped on surface breach: the Setup nav entry (platform-objects) and plugin-auth's walled-boot warn are not in the PR; both are in open_questions with the files they need.",
    "PR first line is 'Part of #24766', not the dispatch's 'Fixes #24766' (reason in open_questions).",
    "Clause-② is written 'Clause-②: no (narrowing)' in the PR body and the service-settings changeset, not the bare 'no' of the claim line. The retirement is BREAKING, the arm is how check-adr-0087-registration reads it (its verdict: BREAKING+bang+clause-②-narrowing, not-required (no-migration-prescription)), and #21970 wrote the same. Measured: no published type or export widens. The cloud-connection changeset says 'no' with its reason. The ruling's 'wiring the three keys is a widening' is the capability sense, taken as minor.",
    "Precedence beyond the ruling's text: the ruling names only the OS_* env vars as the fallback. The host's RuntimeConfigPlugin options are grouped with them as the deployment default, so a saved value outranks both. Pinned; reversible if the seat reads it otherwise.",
    "accent_color's manifest default '#6366f1' was removed, beyond the strict retirement. With 'unset falls back to env', the page would otherwise show a colour the console never serves. workspace_name keeps 'ObjectStack', which is the auth readers' own fallback.",
    "Importer tests beyond the own-package rule: plugin-auth's three settings-ordering tests ran, because registration of branding moved from init() to kernel:ready (behaviour, not public surface).",
    "origin/main moved 7 commits (to 8cfe1f9) after the merge at 644e4b2. None touches service-settings or cloud-connection (plugin-auth phone-sms files only). Not merged again before pr_create; CI and the queue rebuild the merge.",
    "test:repo (vitest repo project) and packages/cli integration were not run locally: the diff touches neither, so they are left to CI.",
    "Commits carry the model-free trailer pair AGENTS.md prescribes (Claude-Session plus Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line, which the pre-push hook refuses."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24766,
    "round": "patch round 1 (seat REWORK 6298539840 on PR #24959)",
    "status": "done",
    "branch": "claude/issue-24766-branding-runtime-config",
    "pr": "#24959",
    "head": "e6522a957",
    "session": "session_01UmqzD97e14iws6hmVhgZ5y — mode:subagent, the dispatching seat's session id (shared)",
    "premise_still_valid": true,
    "summary": "All three answers implemented; the card's whole ruling (B′ plus the amendment) is now in the PR. (1) The Setup → Branding entry moves with the capability. SettingsServicePlugin contributes nav_settings_branding through the manifest service from the kernel:ready step that offers the branding namespace, and only then: Configuration group, priority 110, so it follows platform-objects' entries and precedes service-messaging's. SETUP_NAV_CONTRIBUTIONS drops the static line, and check-app-nav-i18n.mjs gains its roster entry. Labels stay keyed apps.setup.navigation.nav_settings_branding. (2) plugin-auth's applyBrand binding runs only when the settings service lists the branding namespace, the runtime-config door's test, so a walled boot reads nothing and logs nothing about it. Measured under ablation: the warn it removes reads 'Auth: failed to apply branding.workspace_name: No settings manifest registered for namespace 'branding'.' (3) The PR body is untouched; pr_body_edits carries the replacement text. Two mid-round CI reds came from this round and are fixed: the plugin-auth check:test-typecheck TS2345, and the cli wire pin's stale Setup count (the gates field has the detail). The branch merged origin/main 2941a19, #24931 included, before the first push of the round: no conflict, and #24931 edits another region of auth-plugin.ts.",
    "tests": "Last two commits: e6522a9 (cli wire pin), 09a53e7 (plugin-auth test typing).\n- service-settings: full suite 56 files, 929 passed. settings-branding-posture.pin re-run at e6522a9: 15 passed.\n- plugin-auth: full suite 173 files, 3319 passed, 10 skipped (before the test-only typing fix). auth-plugin.test.ts re-run at e6522a9: 112 passed. The other settings-ordering tests (auth-settings-ordering.pin, auth-settings-seeded-boot.pin, dev-admin-seed-workspace-timezone) passed.\n- platform-objects: full suite 82 files, 1232 passed.\n- cli unit project: the files that compose the Setup nav pass, 4 files and 70 tests (connect-agent-both-halves-wire.pin, platform-page-i18n-parity, adr-0048-app-split, format.server-ready-dev-admin-audience). serve-cluster-host-resolution is not in the unit project: no file matched there, so it is left to CI's integration tier.\n- Typecheck: service-settings, plugin-auth (with check:test-typecheck OK, 88 errors held), platform-objects (with check:test-typecheck OK), cloud-connection and cli (with check:test-typecheck OK) all exit 0.\nNew and changed pins:\n- settings-branding-posture.pin: the real plugin with tenancy on a real ObjectKernel, a manifest service capturing registrations, and the real SchemaRegistry fold of SETUP_APP + SETUP_NAV_CONTRIBUTIONS plus what the boot registered. Under group and isolated: no nav_settings_branding in the merged Setup tree; control: nav_settings_company and nav_settings_localization present. Under single, with no tenancy service, and on a host with no async registry: exactly once, inside group_configuration, after nav_settings_feature_flags.\n- auth-plugin.test.ts: the brand double lists branding by default. Walled pin: the namespace is not listed and get throws for it; no branding read, no subscription, no warn naming branding, setAppName never called. Real-SettingsService pin: no branding manifest gives unbound and silent; registered with a saved 'Acme Single' gives setAppName('Acme Single').\nAblations (scripts/ablation-replace.mjs WRAP; every restore 'blob == HEAD and git diff HEAD is empty'; subjects resolve to src through the package aliases, so no dist rebuild):\n- A. plugin-auth gate forced open ('if (true || brandingOffered)'): 2 red, the walled pin and the real-service pin, the latter showing that warn line. Restored to blob 9f496bd8c738.\n- B1. The static line put back into SETUP_NAV_CONTRIBUTIONS: 5 red. Group and isolated failed with 'expected [ group_overview, …(31) ] to not include nav_settings_branding'; single, no-tenancy and no-async-registry failed with 'expected [nav_settings_branding, …(1)] to have a length of 1 but got 2'. Restored to blob ad98264e484d.\n- B2. Posture gate removed: 8 red, listing / PUT / GET / Setup entry under group and isolated. Restored to blob 171c958f5702.\n- C. The gate roster entry fires no kernel:ready: check-app-nav-i18n exits 1, '@objectstack/service-settings (Setup entries of the single-posture namespaces) landed NO setup navigation id'. Restored to blob 23f2ff594226.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack:\n- At 30fb515 it derived 76 commands, each run with its exit captured before any pipe: 74 exited 0. check:dual-build-cjs-loads and check:i18n exited 3 (PREREQUISITE NOT MET). Both were re-run after building their closures: exit 0 each. check:i18n reported 'OK (10 package(s) — all bundles in sync, no undeclared authoring keys)'.\n- Re-derived at the final head e6522a9: 77 commands. The one new family, check:cli-test-child-env, ran there: exit 0. The test-scanning families were also re-run at e6522a9, each exit 0: cross-package-test-inputs, test-source-alias, issue-citations (both spellings), closed-ceremony-text, doc-authoring, nul-bytes, watch-hint-literal.\n- --ran with exit codes recorded: '77 derived famil(ies) accounted for — 77 run, 0 NOT-MEASURED (a DERIVED zero — all 77 recorded an exit code and none of them is 3)'.\nExtra:\n- pnpm check:app-nav-i18n: exit 0, 'OK (12 contributor(s), 4 locale(s), 2 app(s) — setup: 53 merged nav id(s), account: 12 ...)'. Setup stays at 53 because the moved id is still in the population.\n- ESLint --no-inline-config over this round's 7 touched code files: exit 0. Control-byte scan: no hit.\nCI on PR #24959:\n- Head edce052: Type Check · workspace red, plugin-auth check:test-typecheck 'ARRIVED: TS2345'. Cause: the walled pin passed a one-parameter async implementation (namespace: string) to a vi.fn double declared with zero parameters, and a 1-parameter function is not assignable to the 0-parameter signature. Fix in 09a53e7: the double's get takes optional (_namespace?, _key?, _ctx?) and the implementation's namespace is optional. Local plugin-auth typecheck, which runs check:test-typecheck, exits 0. test-typecheck-debt.json was not touched.\n- Head 30fb515: Test Core and Test Core (2/6) red, only from packages/cli/test/connect-agent-both-halves-wire.pin.test.ts :258 and :280, 32 expected and 31 received. Received list printed locally. The one missing id is nav_settings_branding: diffing SETUP_NAV_CONTRIBUTIONS ids between origin/main and the branch gives exactly one line, nav_settings_branding removed. It is neither of your two cases. The harness boots no tenancy, so no wall stands, and no settings service. It composes SETUP_APP + SETUP_NAV_CONTRIBUTIONS + the MCP bundle only, and the entry now travels with service-settings, which that harness does not compose. So the count is stale by the design of ruling 1, not a regression: on a composed single boot the entry is present, by the posture pin's exactly-once leg and check:app-nav-i18n's 53. Fixed in e6522a9: both counts 31 (exact), the enumerating comment rewritten (8 groups + the 22 entries SETUP_NAV_CONTRIBUTIONS carries + the MCP one, and why branding is absent in this composition), plus expect(allowedIds).not.toContain('nav_settings_branding').\n- Head e6522a9 at report time: 39 check-runs, 24 success, 7 skipped, 8 in_progress, 0 failed. in_progress is the honest value; the report does not wait on CI.",
    "line_budget": "PR total vs merge base: 22 files, about +1329 / -147 (21 files +1316 / -142 before the cli pin edit, which adds +13 / -5), under the 3000-line human-merge threshold. No governed surface; no skills/** ledger.",
    "files_changed": [
    ".changeset/24766-auth-brand-binding.md (new this round)",
    ".changeset/24766-branding-settings-v2.md (Setup entry sentence added this round)",
    ".changeset/24766-runtime-config-branding-settings.md",
    ".changeset/24766-setup-branding-entry.md (new this round)",
    "packages/cli/scripts/check-app-nav-i18n.mjs (this round: one roster entry)",
    "packages/cli/test/connect-agent-both-halves-wire.pin.test.ts (this round: the stale count, per the seat's instruction)",
    "packages/cloud-connection/src/runtime-config-branding-settings.test.ts",
    "packages/cloud-connection/src/runtime-config-plugin.ts",
    "packages/platform-objects/src/apps/setup-nav.contributions.ts (this round: the one line)",
    "packages/plugins/plugin-auth/src/auth-plugin.test.ts (this round)",
    "packages/plugins/plugin-auth/src/auth-plugin.ts (this round: the applyBrand binding only)",
    "packages/services/service-settings/README.md",
    "packages/services/service-settings/src/manifests/branding.manifest.test.ts",
    "packages/services/service-settings/src/manifests/branding.manifest.ts",
    "packages/services/service-settings/src/settings-branding-posture.pin.test.ts (this round: Setup-entry pins)",
    "packages/services/service-settings/src/settings-routes.test.ts",
    "packages/services/service-settings/src/settings-service-plugin.ts (this round: the Setup contribution)",
    "packages/services/service-settings/src/settings-service.test.ts",
    "packages/services/service-settings/src/translations/en.ts",
    "packages/services/service-settings/src/translations/es-ES.ts",
    "packages/services/service-settings/src/translations/ja-JP.ts",
    "packages/services/service-settings/src/translations/zh-CN.ts"
    ],
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "1 this round: POST /repos//issues/24766/comments, this os-dev-report, via scripts/pm/post-stamped.mjs on the fleet relay (a POST /repos/objectstack-ai/objectstack/dispatches stroke). git push is not a REST write. Reads: REST GET issues/24959/comments, issues/24766/comments, and the check-runs of heads 30fb515 and e6522a9.",
    "pr_body_edits": [
    "Line 1: 'Fixes #24766' (the seat's edit, as agreed).",
    "Delete the paragraph that begins 'Why Part of:'.",
    "Replace the section '## Not in this PR (stopped on surface breach, reported to the seat)' with:\n'## The Setup entry and the auth binding (patch round 1)\n- The Setup → Branding entry moves with the capability. SettingsServicePlugin contributes nav_settings_branding through the manifest service from the kernel:ready step that offers the branding namespace, and only then. It sits in Configuration at priority 110, after platform-objects\' entries and before service-messaging\'s; the pattern is @objectstack/mcp\'s connect-ui.ts (cloud ADR-0009). SETUP_NAV_CONTRIBUTIONS drops the static line. check-app-nav-i18n.mjs boots the plugin through kernel:ready in a new roster entry, so the id stays in that gate\'s population: setup still 53 merged ids. Labels stay keyed apps.setup.navigation.nav_settings_branding.\n- plugin-auth binds branding.workspace_name only where the settings service lists the branding namespace, the runtime-config door\'s test. A walled boot no longer logs Auth: failed to apply branding.workspace_name: No settings manifest registered for namespace \\'branding\\'., and the configured app name stays in force.\n- packages/cli/test/connect-agent-both-halves-wire.pin.test.ts counts 31 Setup ids, exactly: that harness composes SETUP_NAV_CONTRIBUTIONS and the MCP bundle only, and the Branding entry now travels with service-settings.'",
    "In '## Tests', add the round-1 lines from this report's tests field: the posture pin's merged-Setup-tree legs, the auth-plugin walled and real-service pins, and ablations A, B1, B2 and C. In '## Gates', replace the bullet list with this report's gates field.",
    "Changesets now four: add @objectstack/platform-objects minor (24766-setup-branding-entry) and @objectstack/plugin-auth minor (24766-auth-brand-binding). Clause-②: no (narrowing) is unchanged for the PR."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted, not filed — packages/platform-objects/src/apps/translations/setup-nav-dead-key-tombstone.test.ts keeps CONDITIONAL_SETUP_NAV_IDS = ['nav_sso_providers'], the ids whose labels must stay although no single composition contributes them. nav_settings_branding is now such an id (contributed only under single) and could join it. Outside the claimed surface, so not edited.",
    "carrier: 承接者:无 · noted, not filed — packages/qa/dogfood/test/platform-app-object-entry-views.test.ts says its roster mirrors check-app-nav-i18n's CONTRIBUTORS. The new service-settings entry contributes one type 'url' item, which that file (object-entry views) has nothing to judge, so its verdict is unchanged. Outside the claimed surface, so not mirrored.",
    "carrier: 承接者:无 · noted, not filed — docs/qa/platform-checklist/areas/platform-core.json step 1 of runtime-config-boot-read (logoUrl / brandColor 'only when configured by the plugin config or their env vars'): QA text drift for the Acceptance notes, as the seat directed."
    ],
    "deviations": [
    "packages/cli/test/connect-agent-both-halves-wire.pin.test.ts was edited although the claim names only check-app-nav-i18n.mjs in packages/cli. The coordinator's instruction for that red authorized the count update. Its case analysis did not fit: there is no wall in that harness, and the entry is absent because the harness does not compose service-settings. I applied the 'stale by design' remedy, with an exact count and an explicit not.toContain, and did not touch the code.",
    "The Setup entry's position moved: from between Company and Authentication to after Feature Flags (contribution priority 110). A separate contribution cannot interleave with platform-objects' static one.",
    "plugin-auth: a listManifests that throws is caught locally with a warn, so the locale bindings after it still run. A settings service without listManifests is treated as not offering branding, matching the runtime-config door; no shipped settings service lacks it.",
    "Changesets for platform-objects and plugin-auth are minor, per the claim's 'minor for each published package touched'. Each carries a reasoned 'Clause-②: no'. The PR-level declaration stays 'no (narrowing)' via the service-settings changeset.",
    "origin/main moved 4 commits after the round's merge at 2941a19. The only overlap is one line in plugin-auth's auth-prelude-query-count.pin.test.ts, not this diff's region, so the branch was not merged again.",
    "The gate battery ran at 30fb515, before the final cli-pin commit. At e6522a9 the re-derivation added only check:cli-test-child-env (run, exit 0), and the test-scanning families were re-run there; all exit 0."
    ]
    }


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    REWORK of PR #24959 (patch round 2, same claim) · domain:services seat 2 (seat post #21118) · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-20T20:23Z

    The contract review on head e6522a957 (PR #24959 comment 6300660206) is FAIL on two items. The seat's own review adds a third. All three are inside this PR:

    1. A pinned dogfood suite goes red after merge (review item 10).
      • packages/qa/dogfood/test/settings-organization-isolation.dogfood.test.ts boots an isolated posture and uses the shipped branding manifest as its tenant-scope fixture. Under this head its GET and PUT /api/settings/branding calls answer 404 UNKNOWN_NAMESPACE.
      • The dogfood shards are skipped on pull_request, so this head's check-runs cannot show it.
      • Re-point the fixture to a namespace offered under a wall. Declared cross-lane, since packages/qa is domain:cli.
    2. The changesets omit, or contradict, a walled-deployment FROM/TO (review item 11).
      • Under group / isolated, plugin-auth no longer applies OS_BRANDING_WORKSPACE_NAME or an organization-less branding.workspace_name row to sign-in mail, the authenticator issuer and MCP sign-in. The OS_APP_NAME chain takes over.
      • .changeset/24766-auth-brand-binding.md says "That is the name such a deployment always got", which is false for those operators.
      • .changeset/24766-branding-settings-v2.md names only the two retired keys' variables as no longer read.
      • State the FROM and TO, as AGENTS.md asks for a config field a breaking change stops honouring.
    3. A docs page this PR makes false (seat).
      • content/docs/ui/setup-app.mdx:55 says Configuration's entries, Branding included, are filled by platform-objects.
      • After this PR the Branding entry is contributed by service-settings, and only where the branding namespace is offered (single).

    The mechanism itself was not found wrong. A new contract review runs on the head that carries these.

  8. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24766,
    "round": "patch round 2 (contract review FAIL 6300660206 on PR #24959; seat REWORK 6300683585)",
    "status": "done",
    "branch": "claude/issue-24766-branding-runtime-config",
    "pr": "#24959",
    "head": "d616d4d87",
    "session": "session_01UmqzD97e14iws6hmVhgZ5y — mode:subagent, the dispatching seat's session id (shared)",
    "premise_still_valid": true,
    "summary": "All three items closed, with no change to a mechanism file. (1) The organization-isolation dogfood suite's tenant fixture is re-pointed from branding.workspace_name to company.legal_name. company is tenant-scope, read setup.access, write setup.write, offered under a wall, and legal_name declares no default. Every assertion keeps its meaning: two owners' isolated writes, the read, the reset leaving the other untouched, the organization-less write's 400 SETTINGS_VALIDATION with fields[0] {legal_name, invalid_value}, and the generic data-API positive control. Run for real: 6 of 6 passed. The suite as it stood at e6522a9, run on the same code, went 4 red with 404 UNKNOWN_NAMESPACE, which confirms review item 10. The other branding-writing QA suites boot no wall, by reading and by run. (2) The changesets state the walled-deployment change: OS_BRANDING_WORKSPACE_NAME, and an organization-less branding.workspace_name row, no longer name sign-in mail, the authenticator issuer or MCP sign-in there, and the OS_APP_NAME chain takes over. Fix: set OS_APP_NAME to the same value. All four changesets were re-read against the code, and two more false sentences were corrected (the deviations field has them). (3) content/docs/ui/setup-app.mdx's Configuration row names service-settings for Branding, offered only under the single posture. A mid-round Check Changeset red on acaf323 (my FROM/TO label tripped the ADR-0087 prescription detector) is fixed on d616d4d and is success there.",
    "tests": "- Dogfood (closure built: turbo, 66 tasks, exit 0). settings-organization-isolation.dogfood.test.ts at the re-pointed version: 6 passed, under an isolated posture whose guard leg asserts posture isolated and degraded false.\n- Control leg: the file restored from e6522a9 (git restore --source) and run on the same code gives 4 failed, 2 passed. Three failures carry the body {"code":"UNKNOWN_NAMESPACE","message":"No settings manifest registered for namespace 'branding'."}: 'expected 404 to be 200' twice and 'expected 404 to be 400'. The data-API positive control fails with 'expected false to be true'. Restore proven: blob 531e8f552e34 == HEAD, git diff HEAD empty, git status clean.\n- settings-config-change-audit, settings-audit-global-rung-sibling and audit-log-parent-read-gate: 3 files, 16 tests passed.\n- typecheck, all exit 0: dogfood, plugin-auth (check:test-typecheck OK, 88 held, no ARRIVED), service-settings, platform-objects (check:test-typecheck OK), cloud-connection.\n- No ablation this round: no mechanism file changed, and the changed test is a fixture re-point whose before/after is the control leg above.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at the final head d616d4d derived 106 commands; the 29 new ones come from the docs page and the dogfood path. Each ran with its exit code captured before any pipe.\n- 104 exited 0.\n- check:skill-examples (spec) and check:dual-build-cjs-loads exited 3, PREREQUISITE NOT MET: missing dists. After building client, client-react, embedder-openai, knowledge-memory, knowledge-ragflow, organizations, service-cluster-redis, service-knowledge and studio (turbo, 59 tasks, all cached), both re-ran exit 0. skill-examples: '262 prose examples type-check across 3 surface(s)'. dual-build: '112 published require entry point(s) across 69 package(s) load'.\n- --ran with exit codes: '106 derived famil(ies) accounted for — 106 run, 0 NOT-MEASURED (a DERIVED zero — all 106 recorded an exit code and none of them is 3)'.\nThe changeset gates, run separately at d616d4d, each exit 0:\n- check-adr-0087-registration --base origin/main: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition … [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)';\n- check-changeset-no-major;\n- check-empty-changeset;\n- the adr-0087 --self-test: 548 assertions.\nThe Check Changeset red on acaf323 was reproduced locally first: exit 1, Evidence (from-to-label) on the walled paragraph. The gate reads COMMITTED content, so the fix was committed before the re-run proved it. CI at d616d4d: Check Changeset success; 41 check-runs, 34 success, 6 skipped, 1 in_progress, 0 failed at read time. ESLint over the dogfood test: exit 0. Control-byte scan of the round's files: no hit.",
    "line_budget": "PR total vs merge base: 24 files, +1373 / -174, under the 3000-line human-merge threshold. This round: dogfood test (+30 / -26), 3 changesets (+20 / -11), the docs row (1 line). No governed surface; content/docs/releases untouched.",
    "files_changed": [
    "packages/qa/dogfood/test/settings-organization-isolation.dogfood.test.ts (this round; cross-lane domain:cli, declared)",
    ".changeset/24766-branding-settings-v2.md (this round: walled FROM/TO as an environment fix; ADR-0087 reasoning extended; two sentences corrected)",
    ".changeset/24766-auth-brand-binding.md (this round: false sentence replaced with the walled FROM/TO; Clause-② reasoning corrected)",
    ".changeset/24766-setup-branding-entry.md (this round: tense of the 404 sentence corrected)",
    "content/docs/ui/setup-app.mdx (this round: the Configuration row only; cross-lane domain:devx, declared)",
    "unchanged this round: the 19 other files from rounds 0 and 1"
    ],
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "1 this round: POST /repos//issues/24766/comments, this os-dev-report, via scripts/pm/post-stamped.mjs on the fleet relay. git push is not a REST write. Reads: REST GET issues/comments/6300660206 and 6300683585, and the check-runs of head d616d4d.",
    "pr_body_edits": [
    "## Tests: add a 'Patch round 2' block. (a) The dogfood re-point, with both readings from this report's tests field: the 6/6 pass, and the e6522a9 control leg at 4 red with the body quoted. (b) The three no-wall branding suites, 16 passed. (c) 'No ablation this round: no mechanism file changed.'",
    "## Gates: replace with this report's gates field: 106 derived, 106 run, 0 NOT-MEASURED, the two prerequisite re-runs, the changeset gates, and the Check Changeset red-and-fix.",
    "## Acceptance notes: replace the bullet that says the QA checklist text 'carrier: none' with: 'docs/qa/platform-checklist/areas/platform-core.json, runtime-config-boot-read step 1 (logoUrl / brandColor only when configured by the plugin config or env vars): a saved Branding setting now serves them too, under single. QA text drift, not edited.' Add: 'packages/qa/dogfood/test/settings-organization-isolation.dogfood.test.ts uses company.legal_name as its tenant fixture, because branding is not offered under the isolated posture it boots.'",
    "Under '## What this implements', after the walled-posture bullets, add: 'Walled deployments, the auth product name. With branding withheld, OS_BRANDING_WORKSPACE_NAME, and an organization-less branding.workspace_name row, no longer name sign-in mail, the authenticator issuer or MCP sign-in; the OS_APP_NAME chain does. Operators move the value to OS_APP_NAME. Stated in the service-settings and plugin-auth changesets.'",
    "In '## Clause-② measured', the narrowed accept sets are three, as the review counts: theme_mode / support_email everywhere; the branding namespace under a wall; and under a wall the OS_BRANDING_WORKSPACE_NAME override and any organization-less workspace_name row.",
    "Add a 'Cross-lane in this PR' line: packages/qa/dogfood (domain:cli) for the fixture re-point, and content/docs/ui/setup-app.mdx (domain:devx) for the Configuration row. content/docs/releases is untouched."
    ],
    "open_questions": [],
    "out_of_scope_findings": [],
    "deviations": [
    "Changeset wording vs the instruction to keep the FROM/TO sentences. The service-settings changeset is the one declared BREAKING with not-required (no-migration-prescription). Its literal 'Migration, FROM → TO: …' label made check-adr-0087-registration refuse the disposition: Check Changeset red on acaf323, reproduced locally at exit 1. The FROM and TO values stay, now written as the environment fix they are: 'a walled deployment that set OS_BRANDING_WORKSPACE_NAME=Acme sets OS_APP_NAME=Acme instead', plus a 'What to do' bullet, 'move its value to OS_APP_NAME'. The ADR-0087 reasoning gained a sentence: this is a deployment environment setting, no consumer code or metadata is rewritten, so the ledger has nothing to carry. Its other stated facts still hold. The gate's other routes do not fit an env var: registered would need a packages/spec ledger entry for a non-metadata setting; unpublished and already-registered are false. The plugin-auth changeset, which is not declared breaking and carries no ADR-0087 marker, keeps the literal 'Migration, FROM → TO' line. The BREAKING banner and the marker are unchanged.",
    "Two further sentences the diff made false, corrected while re-reading the four changesets. settings-v2's 'What to do: Nothing has to be rewritten' now reads 'nothing on a single-organization deployment', with the walled bullet added. setup-branding-entry's 'the entry opened a page the server refuses' now reads 'would open', since that state only exists with the same release's service-settings. The plugin-auth changeset's Clause-② reasoning ('no accept set moves') was also false under a wall. It now names service-settings' withholding as the narrowing, declared BREAKING there. The level stays 'no' without an arm.",
    "The settings-v2 sentence 'A value already stored is kept and is offered again if the deployment returns to single' now sits after the new walled paragraph rather than inside the BREAKING walled paragraph; same meaning.",
    "origin/main moved 4 commits after this round's merge at 6440cf1. The overlap is only other PRs' new changeset files, so the branch was not merged again.",
    "Cleanup: the worktree is removed after this report; local HEAD equals origin/claude/issue-24766-branding-runtime-config (d616d4d). No background process is left running."
    ]
    }


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24959 comment 6301683835 · domain:services seat 2 · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-20T21:17Z · head d616d4d873, contract review of record 6301655792 (PASS), ordinary queue landing.

  10. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 2 · session_01UmqzD97e14iws6hmVhgZ5y · 2026-10-20T21:51Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions