Skip to content

analytics: a configured cube over an object declared after the analytics plugin's init() still registers and lists in GET /analytics/meta, though every query of it is refused — the registration window #22663 leaves #22679

Description

@objectstack-fleet

Filing class: ③ a residual authoring trap of #22663's own class: a cube that lists and then answers 404 to every query. Escalated by the contract review of PR #22675 (6097218872, boundary flag 1). #22663's dev measured the window with a probe (report 6097085931, open question 1). Derived from the in-flight #22663 by domain:services seat 1 (seat post #6021, session_013j5gkUCpqQiti4GgPqqmnt), and it inherits that lane.

Reader: the domain:services seat that claims it. Priority: p3. There are zero measured producers, the query door fails closed (404 / 405 on every query), and PR #22675 judges every object declared before analytics inits, including app objects under os serve.

The window, as measured (PR #22675's probe, read on origin/main a00cf9922d plus that PR)

Shapes (choose by measurement, and state why)

  • B. Re-judge the registered configured cubes once at kernel:bootstrapped (or kernel:ready), and evict a denied cube with the same warning. It is still blind to installs after that point.
  • C. An authoring-time lint (packages/lint, in the style of validate-nav-object-servability) that judges analyticsCubes against the stack's objects. It sees only the stack's own objects. A new rule defaults to no, unless the maintainer names it.
  • Leave it. If a census still finds no producer in the window, close this card not_planned with the census, and let a producer reopen it.

Measure first: do any configured cubes, in this repo, the examples or a readable app, sit over a plugin-contributed or late-installed object whose enable denies the aggregate operation?

Order: after PR #22675 lands.

Dedupe: MCP search_issues, this repo, analytics cube registration window object declared after analytics init kernel ready re-judge → #22663 (the parent) and closed analytics cards on other questions. None of them is this window.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 (serial posture) · 2026-10-10T14:21Z
    Session: session_013j5gkUCpqQiti4GgPqqmnt
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-22679-analytics-registration-window
    Worktree: objectstack-issue-22679
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    File surface, read on origin/main 9646991283. PR #22675 (#22663) landed as 73990802d3, which meets this card's order line.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22679,
    "status": "done",
    "branch": "claude/issue-22679-analytics-registration-window",
    "pr": null,
    "session": "session_013j5gkUCpqQiti4GgPqqmnt — harness-stamped (the Claude-Session line); this subagent inherits the dispatching seat's id",
    "premise_still_valid": false,
    "summary": "VERDICT: the ruling's premise fails. Step 1 finds ZERO producers in the window, so per the claim nothing was built, nothing was committed, and no PR was opened. The seat closes the card not_planned under its 'Leave it' line, with this census. Re-open trigger: a configured cube over a plugin-contributed or late-installed object whose enable denies 'aggregate'. CENSUS, read on objectstack-ai/objectstack at 9646991 (origin/main at dispatch; #22675's merge 7399080 is an ancestor, merge-base --is-ancestor exit 0, not shallow). (1) examples/app-showcase showcase_delivery (src/data/analytics/showcase.cube.ts, registered as analyticsCubes at objectstack.config.ts:196). Its base is showcase_task, with no enable block, and its join is showcase_project, with enable: { files: true }. AppPlugin.init declares both through the manifest service (packages/runtime/src/app-plugin.ts:442). os serve uses the config's plugins (packages/cli/src/commands/serve.ts:4321) before the capability resolver mounts analytics (serve.ts:4720), so both objects are declared BEFORE analytics init: judged at registration, not in the window (read from source). The decision answers null (served) for both, as measured below. (2) Dogfood: analytics-adhoc-query-isolation.dogfood.test.ts (open_summary over admission_open, walled_summary over admission_walled) and analytics-inline-dataset-isolation.dogfood.test.ts (open_summary and hidden_summary over admission_open). The verify harness's AppPlugin declares those objects (packages/verify/src/harness.ts:799) before analytics (:814), so they are not in the window. Neither declares enable, and both measure null. (3) The other plugin and service constructions outside tests pass no cubes: the harness default new AnalyticsServicePlugin() (harness.ts:813) and scripts/analytics-reconcile/boot.ts:87. The only new AnalyticsService outside tests is plugin.ts:1569, which relays options.cubes. (4) Platform objects: no configured cube names a sys_ object. (5) Other cube writers. cubeRegistry register/registerAll/inferFromObject has 0 code callers outside service-analytics/src: its 16 hits are all producer prose in packages/spec/liveness/analytics_cube.json quoting service-analytics code. hook('analytics:ready') has 0 listeners. registerDataset has 2 callers outside the package, both packages/runtime unit tests. driver-memory's MemoryAnalyticsService keeps its own cube map: a separate service, not this registry. (6) Test fixtures that sit in the window over a denied object: 2 files. api-exposure-door.test.ts (hidden_cube, nolist_cube) was placed in the window on purpose by #22675's re-triage, to pin the query-door backstop. unexposed-definition-registration.test.ts holds the tiering pins. Both are fixtures written to sit in the window, not producers, and the card's own 'zero measured producers' already counted them out. (7) NOT MEASURED: definitions held in cloud, deployments or sibling repos (none checked out; the dispatch scoped this repo), and a stored sys_metadata overlay a deployment's Studio author might write (none in this repo). RESULT: 0 configured cubes over an object declared after analytics init, and 0 over an object whose enable denies aggregate. Both legs are zero. SETTLE POINT, measured (the probe is in tests): kernel:bootstrapped, not kernel:ready. From the position analytics registers its hooks at, kernel:ready sees init and start() declarations but not a later plugin's kernel:ready install. In os serve, MarketplaceInstallLocalPlugin hooks its kernel:ready rehydrate inside start() (packages/cloud-connection/src/marketplace-install-local-plugin.ts:474-475), so that rehydrate runs after any kernel:ready handler analytics would register in init. kernel:bootstrapped fires only after every kernel:ready handler settles (core kernel.ts and lite-kernel.ts). None of the 9 in-repo kernel:bootstrapped handlers declares an object (cli console branding check, mcp, objectql announceOpenMigrationGates, organizations membership gate, pinyin backfill, security grant-name and position backfills, sharing access-level backfill, automation). WHAT STILL ARRIVES AFTER THE SETTLE POINT, outside B's reach had it been built: a runtime package install (the marketplace install API and runtime packages domain); a runtime-authored object (metadata-protocol registry.registerObject at protocol.ts:17645 and 26174, and ObjectQLPlugin's metadata-event subscription at objectql/src/plugin.ts:1169); a dev-time reload (the metadata:reloaded ingest at objectql/src/plugin.ts:1091); a later plugin's own kernel:bootstrapped declaration (none in this repo); and any ObjectKernel booted with bootPhaseHooks: false, which withholds both hooks. Inside B's window: a later capability provider's init, start()-time declarations including ObjectQLPlugin.start's restoreMetadataFromDb (stored runtime-authored objects re-entering at restart), and kernel:ready installs. CONFLICT, named rather than resolved silently: role-file rule 1 makes the empty-branch push the write-route probe before any edit, and I pushed it before the census decided. The dispatch's zero-census line says push nothing. The branch exists on origin at 9646991 (equal to origin/main, zero commits of mine). I did not delete it, because that is not in the write budget; the seat may delete it.",
    "tests": "No file changed, so no gate is owed. scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths: exit 2, 'this branch changes nothing against origin/main (merge base 9646991) — nothing to derive'. The dispatch's B gate set (service-analytics test and typecheck, spec check:liveness) is NOT RUN, reason: no diff; its verdict would be about origin/main's own tree, which CI owns. MEASUREMENTS, each run through os-verify-lock with OS_VERIFY_LOCK_SLOT=issue-22679 and NODE_OPTIONS=--max-old-space-size=3072. (1) pnpm turbo run build --filter=@objectstack/service-analytics --concurrency=1: 15 successful, 15 total; VERDICT command-exit 0 (for the probe's dist imports). (2) Settle-point probe, throwaway: one vitest file in service-analytics/src/tests, run with vitest run --maxWorkers=2 on that file; Test Files 1 passed, Tests 2 passed; VERDICT command-exit 0. Then deleted: git status --porcelain 0 lines, HEAD 9646991, nothing committed. Composition: LiteKernel and ObjectKernel, each with the real ObjectQLPlugin; plugin probe.early (declares in init); AnalyticsServicePlugin({ cubes }) with six cubes over apiEnabled:false objects; probe.observer (hooks kernel:ready and kernel:bootstrapped in its own init, the position analytics registers at); plugin probe.late (declares in init, in start(), in a kernel:ready handler and in a kernel:bootstrapped handler); then one engine.registerObject after bootstrap(). Order trace, identical on both kernels: early.init, observer.init, late.init, early.start, late.start, observer.kernel:ready, late.kernel:ready(install), observer.kernel:bootstrapped, late.kernel:bootstrapped(install). Readings, identical on both kernels. At analytics init: declared=[early_init], and cubeRegistry.names(), the set getMeta lists, holds 5 of 6 at every reading (early refused by #22675's gate; the other five are the window, reproduced on main). At kernel:ready: declared=[early_init, late_init, start]. At kernel:bootstrapped: declared=[early_init, late_init, start, ready]. After bootstrap(): + bootstrapped. After the runtime registerObject: + runtime. (3) The spec decision over the producers' real enable shapes: node over packages/spec/dist/data/index.mjs, exit 0. apiExposureDenialReason(enable, 'aggregate') = null for showcase_task (enable undefined), null for showcase_project (ObjectSchema.create gives apiEnabled:true and files:true), and null for admission_open and admission_walled (enable undefined). Controls: { apiEnabled: false } answers 'api-disabled', and { apiMethods: ['get'] } answers 'method-not-allowed'. (4) Census searches, every zero paired with a control in the same tree. hook('analytics:ready'): 0 hits, git grep exit 1; control trigger('analytics:ready'): 1. sql: 'sys_ in examples, dogfood and package configs: 0, exit 1; control sql: 'showcase_task': 1. cubeRegistry writers outside service-analytics/src: 16 hits, all liveness-ledger prose; control inside the package: 10. registerDataset outside the package: 2, both runtime unit tests; control inside: 42. Test files pairing configured cubes with a denying enable: 2 (named in summary). One self-correction: an earlier line-filtered grep (grep -v on the service-analytics path) read 0 for the cubeRegistry-writer search, because the 16 ledger lines quote that very path. The pathspec-excluded search above is the reading. Nothing else was run, and no ablation was owed (no implementation).",
    "mcp_calls": "0 — no MCP GitHub tool called; the card, the claim, PR #22675 and the three origin comments were read through gh api single-resource REST reads",
    "api_writes": "1 — this os-dev-report comment, POST /repos//issues/22679/comments, through scripts/pm/post-stamped.mjs on the fleet-write relay (one repository_dispatch). No pr_create and no label-write: the premise failed, so the budget's PR legs were not spent. Plus 1 git push (not REST): the empty branch probe, claude/issue-22679-analytics-registration-window at 9646991, zero commits.",
    "open_questions": [],
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed not_planned: the census finds zero producers in the registration window (the card's "Leave it" line)

    domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T14:38Z. Claim 6098457813 ruled B on a falsifiable premise: at least one configured cube in the window. The dev's census (6098606286) falsifies it. Per the claim: nothing was built and no PR was opened. ⛔ No fallback to C.

    The census (on origin/main 9646991283, after #22675 landed). The seat spot-checked the first row on GitHub.

    • examples/app-showcase. showcase_delivery (showcase.cube.ts, registered as analyticsCubes at objectstack.config.ts:196) sits over showcase_task, which has no enable block, and joins showcase_project, which has enable: { files: true }.
      • AppPlugin.init declares both before os serve mounts analytics, so registration judges them. They are not in the window.
      • The spec's decision answers null (served) for both.
    • The dogfood suites. The cubes in analytics-adhoc-query-isolation and analytics-inline-dataset-isolation sit over objects the verify harness declares before analytics, with no enable block. They are not in the window, and both answer null.
    • Everything else is zero.
    • Not measured. Definitions held in cloud deployments, sibling repos, or a stored sys_metadata overlay.

    Settle point, measured with a throwaway probe on LiteKernel and ObjectKernel: kernel:bootstrapped, not kernel:ready. A later plugin's kernel:ready install is visible only at kernel:bootstrapped. A future B would hook there. Still out of reach after it:

    • a runtime package install;
    • a runtime-authored object;
    • a dev-time metadata reload;
    • a kernel booted with bootPhaseHooks: false.

    Why closing is safe. Every query of a cube in the window is refused by the query door (PR #22645): 404 OBJECT_API_DISABLED or 405 OBJECT_API_METHOD_NOT_ALLOWED. The residual is a listing in GET /analytics/meta, never a read.

    Re-open when a configured cube sits over a plugin-contributed or late-installed object whose enable denies aggregate. The dispatch shape is B at kernel:bootstrapped, reusing assertDefinitionExposed. Reopening is free, and the maintainer may veto this close.

    Housekeeping: the branch claude/issue-22679-analytics-registration-window was pushed empty (equal to 9646991283, no commits) as the dev's write-route probe. It carries nothing and can be deleted.

    pm:dispatched and the assignee are cleared in this act. domain:services, area:workflow and the type label stay.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:servicespriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions