Repository navigation
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
Activity
- addedbugSomething isn't workingSomething isn't workingarea:workflowApprovals and automation — the work that runs without a person driving itApprovals and automation — the work that runs without a person driving it
on Oct 10, 2026 objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsClaim: PM loop round 2 (serial posture) · 2026-10-10T14:21Z
Session:session_013j5gkUCpqQiti4GgPqqmnt
Account:zhuangjianguo(the seat's linked user asGET /useranswers 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 onorigin/main9646991283. PR #22675 (#22663) landed as73990802d3, which meets this card's order line.- Step 1, a census before any edit. In this repo,
examples/**, the platform objects and the dogfood suites, find every configured cube (analyticsCubes/AnalyticsServiceConfig.cubes) whose base or joined object is declared after the analytics plugin'sinit(). The late cases are:- another plugin's later
init(); - any
start(); - a
kernel:readyinstall; - a runtime-authored object.
For each one found, measure whether that object'senablemakesapiExposureDenialReasondenyaggregate. Record the producers found, or a zero with its search.
- another plugin's later
- The ruling on shape, with its premise. The seat rules B, on the premise that step 1 finds at least one producer in the window. B means:
- re-judge the registered configured cubes once, after the boot settles (
kernel:bootstrappedorkernel:ready, whichever step 1 measures as the point where the declarations are complete); - evict a denied cube with the same warning the registration channel already gives;
- reuse
assertDefinitionExposed(PR fix(service-analytics)!: a configured cube or registered dataset over an object the API does not serve is refused at registration, and GET /analytics/meta no longer lists it (#22663) #22675) and the dataset 跨 datasource JOIN 应在编译/发布期就被拒绝,而不是留到查询期才响亮失败(#5033 的后续) #5115 tiering. ⛔ Never a second rule.
- re-judge the registered configured cubes once, after the boot settles (
- If the premise fails (zero producers), push nothing. Report
premise_still_valid: falsewith the census andpr: null. The seat then closes the cardnot_planned, as the card's "Leave it" line says. ⛔ Do not build B anyway. ⛔ Do not fall back to C. - If the census finds a case B cannot reach (a runtime install after
kernel:ready), report it in the census. B's remit is the boot window only. - Files (B only):
packages/services/service-analytics/src/**, for the re-judge, its hook wiring inplugin.ts, and tests;.changeset/22679-*.md, at the level the diff publishes, with FROM → TO;packages/spec/liveness/analytics_cube.json, value-only, only if a#symbolanchor cited there moves. Then also refreshverifiedAton every row it touches.
- ⛔ No C: no
packages/lintrule. A new gate defaults to no, and the maintainer has not named one. ⛔ No otherpackages/specfile. ⛔ Nocontent/docs/releases/. - Stop on breach; explain in the report.
Container & model:S,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate, the default tier builds; a narrowing owes oneCONTRACT_REVIEW_TIERreview before the queue)
Clause-②: no (narrowing) - B stops
GET /analytics/metalisting a cube that no query can ever serve. It adds no export, parameter or option.
Responsibility:this repository's service-analytics: a configured cube over an object declared after analytics init registers and lists, and every query of it then refuses | the registration admission PR #22675 added, whose #5115 tier cannot answer before the declaration exists | an author whose cube sits over a plugin-contributed or late-installed object; step 1 measures whether anyone does today
Thread-read: none
Serial constraints cleared: - PR fix(service-analytics)!: a configured cube or registered dataset over an object the API does not serve is refused at registration, and GET /analytics/meta no longer lists it (#22663) #22675 (analytics: a configured cube or dataset over an
apiEnabled: falseobject registers silently and lists inGET /analytics/meta, then every query of it answers 404 — an authoring trap with no registration-time signal #22663) has landed. None of the 8 open PRs touchesservice-analytics(read 2026-10-10T14:21Z). - In-lane
pm:dispatched: the epic's refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 (plugin-security), whose files are disjoint. - Posture: serial. This is the seat's only card in flight.
Prior rulings read: registration window, kernel:ready, analyticsCubes, re-judge, configured cube → 7 hits, all on the termkernel:readyin ADRs on other subjects (ADR-0062 D5, ADR-0092 D2, ADR-0093 D6, ADR-0094 D4, ADR-0097, ADR-0108 D2). None answers this card's question. Thread: none.
Generated by Claude Code
- Step 1, a census before any edit. In this repo,
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsos-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
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsClosed
not_planned: the census finds zero producers in the registration window (the card's "Leave it" line)domain:servicesseat 1 (#6021) ·session_013j5gkUCpqQiti4GgPqqmnt· 2026-10-10T14:38Z. Claim6098457813ruled 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/main9646991283, after #22675 landed). The seat spot-checked the first row on GitHub.examples/app-showcase.showcase_delivery(showcase.cube.ts, registered asanalyticsCubesatobjectstack.config.ts:196) sits overshowcase_task, which has noenableblock, and joinsshowcase_project, which hasenable: { files: true }.AppPlugin.initdeclares both beforeos servemounts 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-isolationandanalytics-inline-dataset-isolationsit over objects the verify harness declares before analytics, with noenableblock. They are not in the window, and both answernull. - Everything else is zero.
- No other construction outside tests passes cubes.
- No configured cube names a
sys_object. cubeRegistryhas no code writer outsideservice-analytics.analytics:readyhas no listener.- The two test files whose fixtures sit in the window over a denied object were written to pin fix(service-analytics)!: a configured cube or registered dataset over an object the API does not serve is refused at registration, and GET /analytics/meta no longer lists it (#22663) #22675's tiering and query-door backstop. They are not producers.
- Not measured. Definitions held in cloud deployments, sibling repos, or a stored
sys_metadataoverlay.
Settle point, measured with a throwaway probe on
LiteKernelandObjectKernel:kernel:bootstrapped, notkernel:ready. A later plugin'skernel:readyinstall is visible only atkernel: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_DISABLEDor405 OBJECT_API_METHOD_NOT_ALLOWED. The residual is a listing inGET /analytics/meta, never a read.Re-open when a configured cube sits over a plugin-contributed or late-installed object whose
enabledeniesaggregate. The dispatch shape is B atkernel:bootstrapped, reusingassertDefinitionExposed. Reopening is free, and the maintainer may veto this close.Housekeeping: the branch
claude/issue-22679-analytics-registration-windowwas pushed empty (equal to9646991283, no commits) as the dev's write-route probe. It carries nothing and can be deleted.pm:dispatchedand the assignee are cleared in this act.domain:services,area:workflowand the type label stay.
Generated by Claude Code
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 (report6097085931, open question 1). Derived from the in-flight #22663 bydomain:servicesseat 1 (seat post #6021,session_013j5gkUCpqQiti4GgPqqmnt), and it inherits that lane.Reader: the
domain:servicesseat that claims it. Priority: p3. There are zero measured producers, the query door fails closed (404/405on every query), and PR #22675 judges every object declared before analytics inits, including app objects underos serve.The window, as measured (PR #22675's probe, read on
origin/maina00cf9922dplus that PR)enablethe spec'sapiExposureDenialReasondenies.init(), a declaration is known only if it came from a plugin whoseinit()ran earlier. These are not yet known:init();start();kernel:ready;Shapes (choose by measurement, and state why)
kernel:bootstrapped(orkernel:ready), and evict a denied cube with the same warning. It is still blind to installs after that point.packages/lint, in the style ofvalidate-nav-object-servability) that judgesanalyticsCubesagainst the stack's objects. It sees only the stack's own objects. A new rule defaults to no, unless the maintainer names it.not_plannedwith 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
enabledenies 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