Skip to content

analytics: a configured cube or dataset over an apiEnabled: false object registers silently and lists in GET /analytics/meta, then every query of it answers 404 — an authoring trap with no registration-time signal #22663

Description

@objectstack-fleet

Filing class: ③ an authoring trap (Prime Directive 10): the author is told nothing until a query fails. Escalated by PR #22645's contract review (6096186384, boundary flags 5 and 6), from #22634's dev report 6095724958 (finding 3 and the registerDataset Acceptance note). Derived from the in-flight #22634 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. The disclosure is bounded to the author's own naming: getMeta emits cube and member names and titles, never the base object name or rows. The cost is a cube that can never answer.

The gap (read on origin/main 5fb1746611, after PR #22645 if landed)

Ask

Dedupe: MCP search_issues, this repo, analytics meta lists cube over object with apiEnabled false, registerDataset does not refuse … → no card on this gap. The nearest are #20381 and #20356 (closed, registry pollution by ad-hoc requests) and #21082 (closed, lint reads no cube).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-10T10:06Z
    Session: session_013j5gkUCpqQiti4GgPqqmnt
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-22663-analytics-unexposed-cube-registration
    Worktree: objectstack-issue-22663
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    File surface, read on origin/main 156ddfaee4 (PR #22645 landed):


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22663,
    "status": "done",
    "branch": "claude/issue-22663-analytics-unexposed-cube-registration",
    "pr": "#22675",
    "session": "session_013j5gkUCpqQiti4GgPqqmnt — harness-stamped (the Claude-Session line); this subagent inherits the dispatching seat's id",
    "premise_still_valid": true,
    "summary": "Implemented shape (a), the card's preferred shape. The registration doors now ask the decision PR #22645 put at the query door: apiExposureDenialReason(enable, 'aggregate'), through the existing api-exposure-door.ts (new export assertDefinitionExposed; no second rule). They ask it over the definition's base object and declared joins (cubeObjects, the set the query door's first check reads). Each door answers as follows. (1) A configured cube (AnalyticsServiceConfig.cubes, the plugin's cubes, os serve analyticsCubes) over a denied object gets one warn naming the cube, the object and the declaration, and is skipped. The other cubes register, and the boot continues. This reuses the constructor's existing per-definition channel, which a pre-registered dataset that cannot compile already takes (#5115). (2) registerDataset throws a located error carrying the query door's envelope: OBJECT_API_DISABLED/404, or OBJECT_API_METHOD_NOT_ALLOWED/405 with allowed. It registers nothing, and the constructor's datasets take the warn-and-skip channel. (3) A direct write to the service's public cubeRegistry (register/registerAll/inferFromObject) is refused by a new optional CubeRegistry admission hook, which is the single choke point. Refused definitions never reach getMeta. Step 1 census on origin/main ee3ae03: 1 authored cube (showcase_delivery: showcase_task joined to showcase_project; neither declares enable) and 11 example/platform datasets (all request-scoped, never registered). None of them sits over a denied object. There are 0 non-test registerDataset/cubeRegistry writers, so (a) breaks no real producer and (b) was not taken. The only producers were PR #22645's fixtures hidden_cube/nolist_cube, re-triaged: that suite now inits the plugin before declaring its subjects, so its configured-cube rows pin the query door in the window. Timing: a throwaway LiteKernel + real ObjectQLPlugin probe measured a window. An object declared by a plugin whose init() precedes analytics is judged. One declared by a later plugin's init(), or in any start(), is not yet known at registration. It takes the #5115 tier (cannot answer, do not block), and the query door still refuses it. The seat's call on this window is open question 1. Deviations: two lock queue-timeouts (exit 99) behind sibling #22642's long holder; I re-queued under slot issue-22663 and took no reading from a 99. Harness attribution: the harness reminder asked for a commit trailer naming a model and a different PR footer. Per AGENTS.md (which that reminder defers to) commits carry the model-free Claude-Session/Co-authored-by pair, and the PR body carries the session-URL footer.",
    "tests": "Final HEAD dcc38d4 (after merging origin/main, 4 incoming commits, clean merge, pushed); all heavy runs went through os-verify-lock with OS_VERIFY_LOCK_SLOT=issue-22663, NODE_OPTIONS=--max-old-space-size=3072, turbo --concurrency=1 and vitest --maxWorkers=2. (1) pnpm turbo run build --filter=@objectstack/service-analytics: Tasks 15 successful, 15 total. (2) pnpm --filter @objectstack/service-analytics exec vitest run --maxWorkers=2: Test Files 182 passed (182); Tests 4485 passed, 262 skipped (4747). (3) pnpm --filter @objectstack/service-analytics typecheck: tsc --noEmit clean (tsconfig include src covers src/tests). The same three were green pre-merge at d60bf4e. VERDICT command-exit 0. (4) New pins in src/tests/unexposed-definition-registration.test.ts, 12 cases: config cube refused (base and join), the envelope, direct registry write, registerDataset (base 404/405 and join), constructor datasets, the plugin over a real ObjectQL+SqlDriver engine (cubes refused at init and absent from getMeta, registerDataset refuses), the control, and three tiering pins. api-exposure-door.test.ts was reordered; 43 tests across the targeted files passed at d60bf4e. (5) Ablation at c8dae0a via node scripts/ablation-replace.mjs (wrap mode, under the lock). Anchor: the assertDefinitionExposed call in assertRegistrable, hit x1 as declared, x1 to x0; replacement x0 to x1; blob 07cb9454e93f to ea44bf4cd373. Result: Tests 8 failed, 4 passed (12). All refusal pins went red; the dataset control and the 3 tiering pins stayed green, the predicted direction. Restore: blob after restore 07cb9454e93f == HEAD, git diff HEAD empty. Independent re-check: ABLATED marker 0, anchor 1. The pins import the service from src by relative path, with no dist hop, so no rebuild leg was owed. (6) Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 65 at dcc38d4 (identical to the pre-merge set). I ran all 65 plus 4 implicated: check:startup-registry-verdict, check:durability-log-level, check:adr-anchors, and the spec check:error-code-provenance. 69/69 exit 0, each exit captured before any pipe; the dist-reading five ran after the rebuild at this HEAD. --ran: 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero: all 65 recorded an exit code). Verdict lines: startup-registry-verdict reports 45 seams, none recording a verdict the boot can contradict; error-code-provenance OK, every registered-code stamp site listed; nul-bytes OK; the adr-0087 no-migration-prescription exemption accepted; empty-changeset reports 1 declaring changeset added. (7) Timing probe (throwaway, deleted, not committed): at analytics init, early_init true, late_init false, early_start false. Before the change, getMeta listed all 3 cubes; after it, late_init_obj_cube and early_start_obj_cube (the window). Declared to CI and not run locally: repo-wide pnpm lint, and other packages' suites. The public surface change is one additive optional CubeRegistry constructor parameter, and no other workspace package constructs CubeRegistry.",
    "mcp_calls": "0 — no MCP GitHub tool called; card, claim and PR reads went through gh api single-resource REST reads",
    "api_writes": "3 — each through the fleet-write relay (scripts/pm, as objectstack-fleet[bot]), one repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches per write, each executing one op: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, opened #22675 as a draft; read-back shows the body stored byte-identical (14388 bytes); (2) label-write --assign zhuangjianguo, POST /repos//issues/22675/assignees; read-back matches the target; (3) this os-dev-report comment, POST /repos//issues/22663/comments. No label written: the dispatch named none, and the diff publishes, so skip-changeset does not apply. Plus 4 git pushes (not REST): the empty branch probe, d60bf4e, c8dae0a, dcc38d4.",
    "open_questions": [
    {
    "question": "The registration window. A configured cube over an object declared AFTER the analytics plugin's init() still registers and lists in getMeta, and every query of it is refused by the query door. Such objects include: a capability provider that follows analytics in requires order, any start()-time registration, kernel:ready installs, and runtime-authored objects. Is a second judgment owed beyond the #5115 registration-time tiering the dispatch asked to reuse?",
    "options": [
    "A: Leave it as this PR does: judge at registration, with cannot-answer-do-not-block. Cost: none. The window remains for late-declared objects, and the query door stays the fail-closed backstop.",
    "B: Re-judge the registered configured cubes once at kernel:ready (or kernel:bootstrapped), and evict a denied one with the same warn. Cost: a boot-phase hook in plugin.ts, an eviction path on the shared registry, and ordering tests. It is still blind to post-ready installs.",
    "C: An authoring-time lint in packages/lint, analyticsCubes against the stack's objects, in the style of validate-nav-object-servability. Cost: a new rule (fenced off this claim). It sees only the stack's own objects, not plugin-contributed ones, and a new rule defaults to no."
    ],
    "recommendation": "A, on the four axes. Real business need: 0 measured producers fall in the window; the one authored cube sits over app objects, which os serve registers before analytics inits, so they are judged. Long-term soundness: B adds a boot-phase eviction path whose payoff today is hypothetical, while A keeps one judgment point and the query door already fails closed. AI-error prevention: the cube an AI app author typically writes, over its own app's objects, is refused loudly at boot under A, and the window case still fails loudly at every query. Startup focus: no new hook or rule without a measured pull. Take B if a producer over a plugin-contributed or late-installed unexposed object appears."
    }
    ],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted, not filed. An authoring-time check could refuse an analyticsCubes entry whose base or join names an object with enable.apiEnabled false, or a whitelist without list. This would be a packages/lint rule in the style of validate-nav-object-servability, run at os validate / os build, and would catch the pair before boot, inside the registration window too. No producer is measured, the claim fences packages/lint, and a new rule defaults to no; it is recorded in PR #22675 Acceptance notes item 5. Dedupe words: analytics cube lint unexposed object; analyticsCubes apiEnabled false validate; cube registration window kernel:ready; getMeta lists cube over hidden object"
    ]
    }


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment (file surface) · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T11:43Z

    Amends 6096404246.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22663,
    "round": 1,
    "status": "done",
    "branch": "claude/issue-22663-analytics-unexposed-cube-registration",
    "pr": "#22675",
    "head": "3a646f5ffb",
    "session": "session_013j5gkUCpqQiti4GgPqqmnt — harness-stamped (the Claude-Session line); this subagent inherits the dispatching seat's id",
    "premise_still_valid": true,
    "summary": "Round 1 patch. Cause: 16 rows in packages/spec/liveness/analytics_cube.json anchored their producer at service-analytics/src/analytics-service.ts#registerAll. Round 0 replaced the constructor's registerAll call, so Test Core (1/6) failed the spec liveness gate. I reproduced it on dcc38d4 before editing (24 failed, 1 failed, and check:liveness exit 1). Fix: the 16 anchors moved to analytics-service.ts#register, the symbol of the per-cube this.cubeRegistry.register(cube) call that now registers configured cubes. No code changed to fit the anchor. The contract-review addendum (6097218872) is folded in. The 16 rows carry verifiedAt 2026-10-10, and their shared producer string now quotes the code at head; I corrected both quotes, because the serve.ts one (a ?? [] fallback, now resolveStackCollection) was stale since #22288 and a verifiedAt stamp attests the whole producer. The _note no longer says registerAll. The changeset declares Clause-② yes (narrowing) and stays minor. The value-only fence holds: same key paths, 0 status changes, and changed leaves of _note 1, producer 16, verifiedAt 16. No other spec file was touched. I did not PATCH the PR body; the Round 1 text is in pr_body_text, and line 2 is the seat's to update. One main-side red to route: check:platform-checklist exits 1 at head and identically on a clean origin/main 243dd3c tree (control leg), on symbol anchors in files this diff does not touch. No behaviour change was made for the registration window or the dispatch-gates blind spot, as instructed.",
    "tests": "Reproduction at dcc38d4, before any edit, under the lock: pnpm --filter @objectstack/spec exec vitest run --project local scripts/liveness/check-liveness.test.ts gave Tests 24 failed, 47 passed (71), exit 1. vitest run --project repo scripts/liveness/evidence.test.ts gave Tests 1 failed, 41 passed (42), exit 1. pnpm --filter @objectstack/spec run check:liveness gave exit 1 with 16 anchors naming a symbol the file does not contain. After the re-anchor, at 393b179, the same three passed: 71/71, 42/42, exit 0. Spec build exit 0, spec local 642 files / 19180 passed + 1 todo, test:repo 54 files / 915 passed. Final head 3a646f5 (after the addendum commit dabf17b and a clean merge of origin/main 243dd3c). check-adr-0087-registration --base origin/main exit 0, with [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription). check-changeset-no-major --base origin/main exit 0, measured at dabf17b and re-run inside the derived set at 3a646f5. Build closure 15/15. Liveness check test 71/71 exit 0; evidence test 42/42 exit 0; check:liveness exit 0. Spec test local 642 files / 19159 passed + 1 todo, exit 0. test:repo 55 files / 971 passed, exit 0. service-analytics vitest 182 files / 4485 passed, 262 skipped, exit 0. service-analytics typecheck (tsc --noEmit) exit 0. Every VERDICT line reads command-exit 0. Gates: dispatch-gates --commands --repo objectstack-ai/objectstack derived 72 at 3a646f5, 7 new versus round 0: check-dev-prereqs self-test, spec check:empty-state, check:liveness, check:strictness-ledger, check:variant-docs, check:merge-driver, check:platform-checklist. All ran, plus 4 implicated: startup-registry-verdict, durability-log-level, adr-anchors and spec error-code-provenance. Each exit was captured before any pipe; 75 exited 0 and 1 exited 1. --ran reports 72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET, no dist on 64 packages), which is NOT MEASURED. After the full turbo build (72/72, 71 cached) it exited 0: 107 entry points across 66 packages load. check:platform-checklist exited 1 with 7 ABSENT SYMBOL problems in access-security.json and attachments-storage.json. On a control worktree at origin/main 243dd3c it exits 1 with the identical 7, so the red is main-side. Ledger fence proof: a JSON diff of 393b179 against the edit gives same key paths, 0 status changes, and changed leaves {_note 1, producer 16, verifiedAt 16}. The control-byte scan is clean.",
    "mcp_calls": "0 — no MCP GitHub tool called; card, amendment and PR reads went through gh api single-resource REST reads",
    "api_writes": "1 — this round-1 os-dev-report comment, through the fleet-write relay as objectstack-fleet[bot]: one repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches executing the comment op, POST /repos//issues/22663/comments. No PR-body PATCH and no label write. Plus 3 git pushes (not REST): 393b179, dabf17b, 3a646f5.",
    "pr_body_text": "## Round 1 (patch)\n\nHead: 3a646f5ffb. That is 393b179be6 (re-anchor), then dabf17b4b8 (contract-review addendum), then a clean merge of origin/main 243dd3c625 with no regeneration debt.\n\nCause. Test Core (1/6) at dcc38d4413 failed in @objectstack/spec's liveness gate. Sixteen rows in packages/spec/liveness/analytics_cube.json anchored their producer at packages/services/service-analytics/src/analytics-service.ts#registerAll. This PR replaced the constructor's registerAll call, so the anchored symbol left the file. Reproduced on dcc38d4413 before any edit:\n\n- check-liveness.test.ts (local): 24 failed, 47 passed, exit 1.\n- evidence.test.ts (repo): 1 failed, 41 passed, exit 1.\n- check:liveness: exit 1, with "16 anchored citation(s) name a symbol the cited file does not contain".\n\nRound 0's local set missed it. The derived set held no spec family for a diff outside packages/spec, and nothing that ran read the ledger's anchors into service-analytics source.\n\nRe-anchored symbol: analytics-service.ts#register. The constructor now registers configured cubes through this.cubeRegistry.register(cube), one call per cube. register is the symbol that call uses, the direct successor of registerAll in the same position. Nothing in analytics-service.ts changed to fit the anchor.\n\nContract-review addendum (6097218872), value-only in the same ledger. No status, key or row moved, and no other spec file was touched. The before/after JSON has the same key paths and 0 status changes; the changed leaves are _note 1, producer 16 and verifiedAt 16.\n\n- verifiedAt: 2026-10-10 on the 16 rows. Their shared producer string now quotes the code at this head. This covers the serve.ts fallback resolveStackCollection(config, 'analyticsCubes'), which had been stale since #22288 and was a ?? [] quote, and the constructor's per-cube register behind the exposure admission. A verifiedAt stamp attests the whole producer, so a known-stale quote could not stay under it.\n- _note. It now reads "registered one cube at a time by register".\n- Changeset Clause-②: yes (narrowing). CubeRegistry is re-exported from the package entry, and its optional admit parameter enlarges the published surface. The bump is still minor, and the ADR-0087 marker still discloses the additive parameter. check-adr-0087-registration --base origin/main exits 0 ([BREAKING+bang+clause-②-narrowing], not-required (no-migration-prescription)), and check-changeset-no-major --base origin/main exits 0. Line 2 of this body is the seat's to update.\n\nGate exits at 3a646f5ffb. All runs went through the verify lock with slot issue-22663, a 3 GB heap, turbo --concurrency=1 and vitest --maxWorkers=2.\n\n- Liveness pair. check-liveness.test.ts: 71/71, exit 0. evidence.test.ts: 42/42, exit 0. check:liveness: exit 0.\n- Spec suites. test (local): 642 files, 19159 passed and 1 todo, exit 0. test:repo: 55 files, 971 passed, exit 0.\n- @objectstack/service-analytics. 182 files, 4485 passed and 262 skipped, exit 0. Typecheck exit 0.\n- Builds. The service-analytics closure built 15/15. A full turbo run build --filter=!@objectstack/docs built 72/72 (71 cached) for the dist-reading gate.\n- Derived set. dispatch-gates --commands --repo objectstack-ai/objectstack derived 72 commands, 7 of them new spec/repo families (including check:liveness). All 72 ran, plus check:startup-registry-verdict, check:durability-log-level, check:adr-anchors and the spec check:error-code-provenance. 75 exited 0 and 1 exited 1. --ran reports 72 derived, 72 run, 0 NOT-MEASURED and 0 UNRUN, a derived zero.\n- check:dual-build-cjs-loads. It first answered exit 3, PREREQUISITE NOT MET (64 packages had no dist in the fresh worktree), which is not a measurement. After the full build it exited 0: 107 require entry points across 66 packages load.\n- check:platform-checklist exit 1, main-side. It reports 7 problems, all ABSENT SYMBOL anchors. Five are in areas/access-security.json, against metadata-protocol/src/protocol.ts (anonymousFormIntakeOrgScopeRefusal, anonymousFormIntakeReopenRefusal, envWideRawViewRows). Two are in areas/attachments-storage.json: #canEdit, and the symbol-anchor floor at 27 of 28. None of those files is in this diff. Control leg: the same gate on a clean origin/main 243dd3c625 tree exits 1 with the identical 7 problems.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: the seat (main-side red; not in this diff) · noted, not filed. pnpm check:platform-checklist exits 1 on origin/main 243dd3c, measured on a clean control worktree, with 7 problems. Five are in docs/qa/platform-checklist/areas/access-security.json: ABSENT SYMBOL packages/metadata-protocol/src/protocol.ts#anonymousFormIntakeOrgScopeRefusal, #anonymousFormIntakeReopenRefusal and #envWideRawViewRows (each 0 occurrences in protocol.ts at origin/main). Two are in areas/attachments-storage.json: packages/services/service-storage/src/attachment-access-hooks.ts#canEdit is present as text but not as a declaration, and SYMBOL ANCHORS LOST 27 against a floor of 28. Not bisected. Dedupe words: platform-checklist absent symbol protocol.ts; anonymousFormIntakeReopenRefusal anchor; attachment-access-hooks canEdit anchor floor"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22663,
    "round": 2,
    "status": "done",
    "branch": "claude/issue-22663-analytics-unexposed-cube-registration",
    "pr": "#22675",
    "head": "0dd4426835",
    "session": "session_013j5gkUCpqQiti4GgPqqmnt — harness-stamped (the Claude-Session line); this subagent inherits the dispatching seat's id",
    "premise_still_valid": true,
    "summary": "Round 2: two value-only fixes to stale leaves under the round-1 verifiedAt stamp, in packages/spec/liveness/analytics_cube.json only (review 6097791315, flag ③.4). (1) The first evidence citation of joins.children.name quoted a joinTable line that is gone from native-sql-strategy.ts. It is re-sited at hop-object.ts#resolvePathHops, quoting const joined = joins?.[alias]?.name; verbatim, with native-sql-strategy.ts#qualifyAndRegisterJoin kept as the LEFT JOIN emitter (object: hop.object, verbatim). The other three citations are unchanged. (2) In the 16 producer strings, the configKey declaration clause is re-sited at packages/core/src/capability-providers.ts#CAPABILITY_PROVIDERS. The serve.ts threading quote stays at serve.ts#CAPABILITY_PROVIDERS, which is the resolver's own declared handle (const CAPABILITY_PROVIDERS = Serve.CAPABILITY_PROVIDERS, line 4593) that the loop indexes; I chose it over the enclosing run() method, a 3,000-line method whose name would anchor nothing specific. That clause now also quotes spec.configKey === 'analyticsCubes'. Every quote occurs exactly once at head, and every anchor names a declaration in its cited file. Fence against origin/main: same 91 key paths, 0 status changes, changed leaves _note 1, verifiedAt 16, producer 16, evidence 1. Nothing else was touched. origin/main had not moved (243dd3c is an ancestor of head), so no merge was needed. I did not PATCH the PR body; the round-2 section is in pr_body_text.",
    "tests": "Head 0dd4426; all heavy runs went through os-verify-lock with OS_VERIFY_LOCK_SLOT=issue-22663, NODE_OPTIONS=--max-old-space-size=3072, turbo --concurrency=1 and vitest --maxWorkers=2, each exit recorded before any pipe. Full turbo run build --filter=!@objectstack/docs: Tasks 72 successful (72), exit 0. pnpm --filter @objectstack/spec exec vitest run --project local scripts/liveness/check-liveness.test.ts: Tests 71 passed (71), exit 0. vitest run --project repo scripts/liveness/evidence.test.ts: Tests 42 passed (42), exit 0. pnpm --filter @objectstack/spec run check:liveness: exit 0. Spec test:repo: Test Files 55 passed, Tests 971 passed, exit 0. dispatch-gates --commands --repo objectstack-ai/objectstack derived 72 at 0dd4426 (the same set as round 1). All 72 ran, plus startup-registry-verdict, durability-log-level, adr-anchors and spec error-code-provenance: 75 exited 0 and 1 exited 1. check:dual-build-cjs-loads exit 0 (107 entry points across 66 packages load). check:platform-checklist exit 1 with 7 problems, a line-for-line diff identical to round 1's clean origin/main 243dd3c control, so the red is main-side and in no file of this diff. --ran: 72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero. Fence proof by JSON walk: against origin/main, same key paths (91), status changes 0, changed leaves {_note 1, verifiedAt 16, producer 16, evidence 1}; against 3a646f5, {producer 16, evidence 1}. The edit used literal splits with exact hit counts (evidence x1, producer x16) and no JSON re-serialisation. The blob moved a780de2e24c7 to 79771f0a0700. The control-byte scan is clean.",
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "1 — this round-2 os-dev-report comment, through the fleet-write relay as objectstack-fleet[bot]: one repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches executing the comment op, POST /repos//issues/22663/comments. No PR-body PATCH and no label write. Plus 1 git push (not REST): 0dd4426.",
    "pr_body_text": "## Round 2 (ledger)\n\nHead: 0dd4426835 (one commit on 3a646f5ffb). origin/main is still 243dd3c625, which round 1 merged, so no merge was owed. Only packages/spec/liveness/analytics_cube.json changed, and only values. The contract review of 3a646f5ffb (6097791315, flag ③.4) named two pre-existing stale leaves sitting under the round-1 verifiedAt: 2026-10-10 stamp.\n\n1. joins.children.name, first evidence citation. It quoted const joinTable = cube?.joins?.[alias]?.name ?? alias at native-sql-strategy.ts#qualifyAndRegisterJoin. joinTable has 0 occurrences in that file at head. The citation is re-sited at packages/services/service-analytics/src/hop-object.ts#resolvePathHops, quoting const joined = joins?.[alias]?.name; verbatim (tier 1 of the one hop resolver). It keeps native-sql-strategy.ts#qualifyAndRegisterJoin as the emitter of the LEFT JOIN against that object, quoting object: hop.object, which is verbatim at head. The row's other three citations are unchanged.\n\n2. The 16 producer strings.\n\n- The configKey declaration clause is re-sited at packages/core/src/capability-providers.ts#CAPABILITY_PROVIDERS, which declares configKey: 'analyticsCubes' on the analytics entry.\n- The serve.ts threading quote stays where it lives, at packages/cli/src/commands/serve.ts#CAPABILITY_PROVIDERS. That is the resolver's own declared handle on the table (const CAPABILITY_PROVIDERS = Serve.CAPABILITY_PROVIDERS), which the resolver loop indexes. The clause now quotes the test it applies, spec.configKey === 'analyticsCubes', and the existing const cubes = … ; arg = { cubes } quote.\n- Every anchor names a declaration in its cited file, and every quote occurs exactly once at head.\n\nFence proof. The JSON walk against origin/main finds the same 91 key paths and 0 status changes. Changed leaves by field: _note 1, verifiedAt 16, producer 16, evidence 1. Against the round-1 head, only producer 16 and evidence 1 moved.\n\nGates at 0dd4426835. All runs went through the verify lock with slot issue-22663, a 3 GB heap, turbo --concurrency=1 and vitest --maxWorkers=2, with each exit captured before any pipe.\n\n- check-liveness.test.ts (local): 71/71, exit 0.\n- evidence.test.ts (repo): 42/42, exit 0.\n- pnpm --filter @objectstack/spec run check:liveness: exit 0.\n- Spec test:repo: 55 files, 971 passed, exit 0.\n- Full turbo run build --filter=!@objectstack/docs: 72/72 tasks, exit 0.\n- dispatch-gates --commands --repo objectstack-ai/objectstack derived 72 commands, the same set as round 1. All 72 ran, plus 4 implicated ones. 75 exited 0 and 1 exited 1. --ran reports 72 derived, 72 run, 0 NOT-MEASURED and 0 UNRUN, a derived zero.\n- check:platform-checklist still exits 1 with the identical 7 main-side ABSENT SYMBOL problems that round 1's clean origin/main 243dd3c625 control showed. None of them is in this diff.",
    "open_questions": [],
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT (seat review, patch round 2): PR #22675 at head 0dd4426835. The analytics registration doors refuse a definition over an object the API does not serve

    domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T13:47Z.

    • Claim 6096404246, amended 6097143716 (one packages/spec/liveness file, value-only).
    • Reports: round 0 6097085931, round 1 6097648815, round 2 6098050717.
    • Read against GitHub, and the PR head fetched into a seat-owned ref, not the reports.

    Review route. The PR declares Clause-②: yes (narrowing):

    • it narrows the accept set at three registration doors;
    • CubeRegistry, re-exported from the package entry, gains one optional constructor parameter, which widens the public surface.

    The contract-review-tier records are on the PR:

    • 6097218872 on dcc38d4413: FAIL, a red liveness shard and the undeclared widening;
    • 6097791315 on 3a646f5ffb: PASS, with flag ③.4 naming two stale ledger leaves under the fresh verifiedAt. The seat folded the flag into the branch (6097801200).
    • 6098145097 on 0dd442683534bf37b941ae9d4b2050e668f397f9: PASS. Served-tier: CONTRACT_REVIEW_TIER, Local-runs: none, an isolated at-tier subagent adopted by this seat. ③.4 is discharged, and nothing is owed before the queue.

    Shape. Draft, base main. Line 1 is Fixes #22663; line 2 is Clause-②: yes (narrowing). 7 files, +589 / −59. NOT governed: check-governed-merges --pr 22675 finds 0 of 7 paths, 648 changed lines. The changeset grades @objectstack/service-analytics minor, BREAKING as an accept-set narrowing; no major.

    The change, as read in the diff

    Evidence read. The dev's derived set at the head: 72 derived, 72 run, 0 NOT-MEASURED. The one non-zero is check:platform-checklist, main-side, below. check:liveness, the liveness pair and spec test:repo all exit 0. service-analytics: 4485 passed, typecheck exit 0.

    CI at 0dd4426835: 30 success and 5 skipped, read latest-run-per-check-name. The skips are Auto Label, Build Docs, Check PR Size, Console Pin Gate and Packed-tarball smoke (opt-in), all rostered. The seven required contexts are all success. mergeable_state: clean.

    The PR's Acceptance notes and the dev's findings, disposed

    Landing: ready plus auto-merge through the queue, in this act. After this lands, the seat moves to serial dispatch, one card at a time, on the maintainer's instruction.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:services seat 1 (#6021) · session_013j5gkUCpqQiti4GgPqqmnt · 2026-10-10T14:19Z


    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