Skip to content

os info reports stats.objects: 1 and objects: [] in the SAME --json payload for a packages[]-only project — its four detail reads are still top-level-only #17790

Description

@claude

Symptom

os info renders its detail sections — Objects:, Agents:, Apps: — and its --json objects array from config.objects / config.agents / config.apps directly, off the top level. On an ADR-0130 D4 / option-B project (every definition inside packages[], none flattened up) those reads see nothing, so the command contradicts itself within one run.

The --json face is the sharp half, because it is the one machines read:

{ "stats": { "objects": 1, "apps": 1, "views": 1 }, "objects": [] }

stats.objects and objects[] describe the same project in the same payload and disagree. Nothing in the payload distinguishes "this project has no objects" from "this reader could not see them".

The text face shows the same gap as an absence rather than a contradiction: Data: 1 Objects 2 Fields prints, and the Objects: section that normally follows it is simply not there.

Minimal repro

objectstack.config.ts — one package, nothing at the top level except the envelope:

export default {
  manifest: { id: 'com.example.ob', name: 'ob', version: '1.0.0', type: 'app', namespace: 'ob' },
  packages: [
    { manifest: { id: 'com.example.ob', name: 'ob', version: '1.0.0', type: 'app', namespace: 'ob',
        objects: [
          { name: 'ob_order', label: 'Order', sharingModel: 'private',
            fields: {
              number: { type: 'text', label: 'Number' },
              ghost: { type: 'lookup', label: 'Ghost', reference: 'ob_order' },
            } },
        ],
        views: [
          { name: 'ob_order_views', object: 'ob_order',
            list: { label: 'Orders', type: 'grid',
              data: { provider: 'object', object: 'ob_order' },
              columns: [{ field: 'number' }, { field: 'ghost' }] } },
        ],
        apps: [
          { name: 'ob_app', label: 'OB',
            navigation: [{ id: 'nav_orders', type: 'object', objectName: 'ob_order', label: 'Orders' }] },
        ] } },
  ],
};

Measured through the real binary (node packages/cli/bin/run.js) on branch claude/issue-17527-metadata-stats-package-fold:

os info --json   exit 0   stats.objects = 1 | stats.apps = 1 | stats.views = 1
                          objects[] length = 0

os info          exit 0   Data: 1 Objects  2 Fields
                          UI: 1 Apps  1 Views
                          (no `Objects:` section)

Control — the identical object authored at the TOP LEVEL, same command, same binary: Objects: prints ob_order (2 fields, user) — Order, and --json carries the one entry. So the absence is produced by the reader, not by the stack.

Cause, located

packages/cli/src/commands/info.ts — four reads, all off the top level, none of them going through the package-owned-collection seam:

info.ts:50    objects: (config.objects || []).map((o: any) => ({ … }))   # the --json array
info.ts:75    if (config.objects && config.objects.length > 0) { … }     # the `Objects:` section
info.ts:91    if (config.agents && config.agents.length > 0) { … }       # the `Agents:` section
info.ts:103   if (config.apps && config.apps.length > 0) { … }           # the `Apps:` section

packages/cli/src/utils/stack-collections.ts already ships the primitive these need — resolveStackCollection(stack, key) answers the caller's original expression first and consults packages[] only when the top level does not carry the key, so adopting it cannot change what any stack the platform emits today reports.

Relationship to #17527

Found while landing #17527 (PR #17775), and not created by it. #17527 folds packages[] into collectMetadataStats, which is the reader behind the summary — a different reader from these four, on a different path. Before that fix both halves of os info reported zero and agreed with each other; the fix corrects the summary and leaves the detail reads where they were, which is what turns a consistent wrong answer into a visible contradiction. The --json self-contradiction is therefore newly visible, not newly true: objects[] was empty on this stack before the fix as well.

Why it was filed rather than folded into that PR

Two reasons, and the second is the one that decided it.

  1. The card os validate, os build and os info all report Data: 0 Objects for a project whose metadata lives only in packages[] — collectMetadataStats reads the top level alone, and under --strict the false No objects defined warning gates #17527 carries is explicit that the summary's presentation is the question it answers, and it answers only that one.
  2. os info --json's objects array is a machine face. Whether an option-B project's detail listing should be a flat union (what resolveStackCollection would give) or grouped per package is a presentation decision nobody has made, and making it silently inside a fix for the summary would settle a published output shape by accident.

Deduplication

One targeted repo-scoped REST read — GET /repos/objectstack-ai/objectstack/issues?state=open&labels=domain:cli&per_page=100, 44 open non-PR cards, page 2 empty — then grepped locally over title + body. collectMetadataStats as the positive control returns exactly 1 hit (#17527), so the greps are live and the zeroes are readings.

No open card names these four reads or the --json objects array. Scope of the read is stated so it can be re-run: open cards carrying domain:cli only.


Generated by Claude Code

Activity

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions