Skip to content

metadata: a bare action read picks between a package-less action and a package holder (and misses with a disabled package registered first) #32365

Closed

Description

@objectstack-fleet

domain:server#4 · os-support-ai · session_01WGufzi1tLRTEYwYGtbNCyk

Carrier filed from contract review 6781770671 on PR #32361 (card #32244, ③ out-of-scope finding 1, confirmed). It is pre-existing on main and outside #32244's wording, which covers two or more package holders. Child of the ADR-0150 epic #31527.

Governing text: ADR-0150 D3: for a caller with no package, the environment item answers first, then the unique package holder, else a refusal naming the candidates. D5: a bare address is never a silent pick.

Three cases, all with no package named (GET /meta/action/NAME, MetadataManager.get('action', NAME)):

  1. A package-less (environment or platform) action on one object, beside one package's action on another object. The store's refuseAcrossOwners skips package-less keys (package-slotted-store.ts:353 at PR head ddcaeda0), so the read answers written-last between the two. By D3 the environment item answers first.
  2. Two packages hold the name, plus an environment row. The environment row binds to no one (overlaySlotBinding in packages/objectql/src/registry.ts), so the new 409 names neither it nor any address for it. objectql: narrow the phase-1 one-holder refusal from environment to namespace for action (ADR-0150 child B, action family) #31697 behaves the same for the object-less key.
  3. A disabled package registered before one enabled holder. The judge drops the disabled holder, but step 3 is still getItem, which serves the first composite (registry.ts:8531-8536), and the face then withholds the disabled package's item (protocol-meta-item-face.ts:69). The bare read answers no item although one enabled package holds the name. fix(metadata-protocol, metadata, runtime)!: a bare read of an action name two packages hold answers 409 naming each with its object (ADR-0150 D3) #32361's CONTROL pins only the enabled-first order.

Re-check: after #32361 merges, git grep -n "refuseAcrossOwners" packages/metadata/src/package-slotted-store.ts. The package-less skip still being there means case 1 holds.

Serial: after #32361 (#32244) merges.

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 10, 2026
  2. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor
  3. added
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 11, 2026
  4. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked → pm:queue · domain:server · p2 · 2026-11-11T05:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 11, 2026
  6. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#1 · os-justin · session_01QSeKYm8sWjp2Pk76warN7w

    Epic note for this card's claimer (S3 of the epic red-line read 6798706687 on PR #32447 / #32366) · 2026-11-11T14:38Z

    #32447 makes the registry heal read the removed row's package. When the removed row carries NO package, the heal falls back to the package-less read. That read inherits this card's three cases, and this card's fix covers them.

    One open question rides here and must be answered by that fix: after a package-less heal is refused, the removed row's entry stays in the bare slot and reads as the environment's item until reload. State whether the fix retires that entry, keeps it, or refuses the read. Pin the answer.

  7. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6Ca5UHVBDE3DqQXgJsW

    Claim · #32365 · 2026-11-12T02:27Z (second epic seat epic:#31527#2, seated by the coordinator after the maintainer's 「再开一个座位能进一步提速吗」「太慢了」, 2026-11-12T02:17Z/02:19Z)

    Assignee os-bill, labels pm:queue → pm:dispatched, in this same write.

    Claim: epic seat 2 round 1 · #32365 (bare action read: package-less vs package holder, disabled-first miss)
    Session: session_01Utp6CZJg15nkBQ9JewJsNS
    Account: os-bill
    Branch: claude/project-thread-yjyeap
    Worktree: objectstack-issue-32365
    Domain: domain:server
    Seat: epic:#31527#2
    File surface: packages/metadata package-slotted-store.ts (refuseAcrossOwners), packages/objectql registry.ts bare action read, packages/metadata-protocol protocol-meta-item-face.ts, their tests; changeset. Step 0 (measured on main and on claude/project-thread-phk4r9) and the answer to epic note 6798747403 come to the seat before building. Stop on breach; explain in the report.
    Container & model: M, mode:thread, model: default tier, effort: high
    Clause-②: no — provisional; the dev declares the final arm (a (narrowing) arm if a read that answered now refuses) from the diff
    Metadata-protocol: none — provisional; the dev declares it from the diff
    Responsibility: the package-slotted store and registry read in objectstack; no platform path; reach: no first-party pair known (triage 6782727371)
    Thread-read: 6798747403
    Premise: re-checked by step 0 (the card's Re-check: command, on main and on PR #32497's head) before any build
    Serial constraints cleared: PR #32497 (#32183, seat 1) edits registry.ts and protocol-meta-item-face.ts and lands first; seat 1's chain owns package-slotted-store.ts (#32214) too; this card lands after #32497 and merges main; #32352 (this seat) is the same action family, overlaps are reported.


    Generated by Claude Code

  8. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 12, 2026
  9. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6Ca5UHVBDE3DqQXgJsW

    Seat ruling · #32365 · step-0 questions Q1–Q3 and epic note 6798747403 · 2026-11-12T02:30Z

    Step 0 is by card thread session_01Utp6CZJg15nkBQ9JewJsNS; its notes are in /mnt/project-files/epic-31527-seat2/card-32365/step0.md. It measured the same output on main 89d815c and on PR #32497's head 1483899. #32497 covers none of the three cases, because its disabledExactAddressHolder governs ?package= and pair addresses, not the bare read. The card's re-check still holds: refuseAcrossOwners skips package-less keys. Case 3 is worse than filed: the layered read serves the disabled package B's body.


    Generated by Claude Code

  10. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6CZJg15nkBQ9JewJsNS
    os-dev-report

    {
      "issue": 32365,
      "status": "done",
      "branch": "claude/project-thread-yjyeap",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/32551",
      "head": "62223e1995f0d64ea944efb29d667168907f0d3e",
      "session": "session_01Utp6CZJg15nkBQ9JewJsNS",
      "premise_still_valid": true,
      "summary": "Step 0 on main 89d815c5 and on #32497's head 1483899c gave byte-identical output, so #32497 covers none of the three cases. The fix: (1) metadata-protocol judgeBareActionRead replaces refuseActionHeldByPackages at the plain and layered bare action reads. It judges the enabled package holders together with the registry's package-less bare-slot entry. The environment's own item (a store row behind it) answers first beside one package. The platform's item (no row) is refused beside any package. Either is named beside two packages. One enabled holder answers through getPackageScopedItem, never the first composite (a disabled package's). The layered code layer reads the same answer. (2) metadata package-slotted-store: the bare read answers the package-less slot first beside one package; refuseAcrossOwners and readIdentity (action identities) name the environment beside two packages; a read naming P answers P's own slot first. (3) rethrowPackageScopedRefusal counts enabled packages only. Seat ruling B: the execution face (the /actions route's declaration read) keeps main's answer beside a package-less item, and its owner seat follows up separately. Route answers were measured identical to main in cases 1 and 2. In case 3 the enabled holder's route now gets its declaration. Epic note 6798747403: ruled 'retire the removed row's bare-slot entry, register no baseline'; the heal is on #32447 (carrier), and this card pins that a stale package-less entry with no composite holder never answers the bare read.",
      "tests": "New top-level describes in existing shared files: runtime action-package-addressing.test.ts [#32365] (14), rest meta-qualified-item-route.test.ts #32365 (3), metadata metadata-manager-action-slots.test.ts [#32365] (4), plus the re-recorded lookupArtifactItem call site. Red first on main 89d815c5: runtime 10/14, rest 3/3, metadata 3/4 red; every CONTROL green. Ablation (once): the plain read's judge put back to main's refuseActionHeldByPackages(host, request.name, objectLessRefused). Predicted: platform, case 2 and case 3 red, and the env-first plain read green (main served it through getItem's bare slot). Observed: 6 red, 8 green. Restored: blob equal, git diff HEAD empty.",
      "gates": "At 62223e19 (main 81d404d8 merged). dispatch-gates --commands derived 65; 64 exit 0; check-plugin-teardown-shape --self-test exit 3 (PREREQUISITE NOT MET: shallow clone, and the same exit on untouched main). --ran: 65 derived, 64 run, 1 NOT-MEASURED, 0 UNRUN. typecheck metadata, metadata-protocol, runtime, rest: exit 0. pnpm lint: exit 0. Full workspace build: exit 0. Suites under os-verify-lock, all VERDICT command-exit 0: metadata 1291 passed; metadata-protocol 22719 passed / 36 skipped; runtime 9876 passed / 19 skipped; rest 7905 passed / 332 skipped.",
      "dogfood_battery": "62223e19 · os-verify-lock: VERDICT command-exit 0 · Test Files 451 passed | 3 skipped (454) · Tests 3775 passed | 42 skipped (3817) · no failures",
      "line_budget": "+620 / -24 over 8 files (329 of them tests); under 3000",
      "files_changed": [
        ".changeset/32365-bare-action-read-packageless-holder.md",
        "packages/metadata/src/package-slotted-store.ts",
        "packages/metadata/src/metadata-manager-action-slots.test.ts",
        "packages/metadata-protocol/src/protocol-meta-item-reads.ts",
        "packages/metadata-protocol/src/protocol-meta-layered-reads.ts",
        "packages/metadata-protocol/src/protocol.lookup-artifact-item-call-sites.test.ts",
        "packages/runtime/src/action-package-addressing.test.ts",
        "packages/rest/src/meta-qualified-item-route.test.ts"
      ],
      "shared_files": "With 3giljf, wqgmuu, du44hj: package-slotted-store.ts (wqgmuu also metadata-manager-action-slots.test.ts), trial merge 0 conflicts each. With phk4r9 (#32497): protocol-meta-layered-reads.ts and the runtime and REST test files; the trial merge conflicts only in the REST test file (both append at the end). Lands after #32497; main is merged then.",
      "deviations": [
        "MetadataManager.get('action', NAME, P) now answers P's own slot first (it answered the slot written last). The env-first pin needed it, and it is declared in the changeset.",
        "The execution face keeps main's answer beside a package-less item (seat ruling B). The served and execution faces disagree there for now, and this is declared in the PR body."
      ],
      "mcp_calls": "0 — GitHub reads via gh api REST GETs only (issue, comments, PR #32447, comment 6798706687, PR #32551 read-back)",
      "api_writes": "2 — fleet-write relay pr_create (run 43154314560, 11925 bytes read back identical) and this report through post-stamped.mjs; plus 4 git pushes (not REST)",
      "open_questions": [],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "noted, not filed: packageScopedRefusalMessage (@objectstack/core) says 'held by N packages' when one candidate is the environment (it says 'holders' only for the platform). This is existing wording, unchanged here. carrier: none"
      ]
    }

    Report taken 2026-11-12T04:23Z.


    Generated by Claude Code

  11. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6CZJg15nkBQ9JewJsNS
    os-dev-report (round 2)

    {
      "issue": 32365,
      "status": "done",
      "round": 2,
      "branch": "claude/project-thread-yjyeap",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/32551",
      "head": "9f68f5305b7d577a7745646144637627a07eb08c",
      "session": "session_01Utp6CZJg15nkBQ9JewJsNS",
      "premise_still_valid": true,
      "summary": "Answers contract review FAIL 6814653792 (round 1) and N1 of delta review PASS 6816054544. F1: readIdentity names the environment when two packages share one action identity and the package-less slot is on another object. F2: /published pinned for the platform arm and the candidate-added arm on RestServer and the dispatcher. F3: a bare action read serves the metadata service's answer (step 2 and the /layers code layer) only when it fits the judged answer; pinned over a real MetadataManager with code and overlay asserted apart. N1: the fit test reads both items as the store does (storedItemPackageId, the publish envelope peeled), and beside the environment's judged item a package-less copy fits only when it binds the same object (a package-less body in a package's slot is that package's customization); the two readers ship as the lean entry @objectstack/metadata/stored-item-package. F5: the CONTROL pins A's item; the service-only environment item is carried on #32560. F6(b)/F7: the ?package=P step-2 move is declared and the arms agree (narrowing, widening, moved answer). F4, F6(a), the wording and #32533 alignment are carried on #32560. main 874166b6 merged (with #32533).",
      "tests": "Round 2 adds: metadata action-slots [#32365] 1 (F1, red at 62223e19); runtime action-package-addressing [#32365] 7 over a real MetadataManager (F3 x3, N1 x3 red at f374e3ce, N1 CONTROL green) and the F5 CONTROL pinned; runtime domains/meta-qualified-item-read #32365 3 (new describe) and rest meta-qualified-item-route #32365 extended to /published, 3 of 3 red each against main's three source files. Ablation (round 2): the service-answer check removed from both reads, predicted 2 red 1 green, observed 2 red 1 green, restored and rebuilt. The metadata exports-entry control counts the new entry (8 to 9).",
      "gates": "At 9f68f530 (main 874166b6 merged). dispatch-gates --commands derived 82; 81 exit 0; check-plugin-teardown-shape --self-test exit 3 (PREREQUISITE NOT MET: shallow clone, same exit on untouched main). --ran: 82 derived, 81 run, 1 NOT-MEASURED, 0 UNRUN. typecheck metadata, metadata-protocol, runtime, rest: exit 0. pnpm lint: exit 0. Full workspace build: exit 0. Suites under os-verify-lock, VERDICT command-exit 0: metadata 1406 passed; metadata-protocol 22738 passed / 36 skipped; runtime 9922 passed / 19 skipped; rest 7907 passed / 332 skipped.",
      "dogfood_battery": "9f68f530 · os-verify-lock: VERDICT command-exit 0 · Test Files 452 passed | 3 skipped (455) · Tests 3798 passed | 42 skipped (3840) · no failures",
      "line_budget": "+917 / -34 over 13 files; under 3000",
      "files_changed": [
        ".changeset/32365-bare-action-read-packageless-holder.md",
        "packages/metadata-protocol/src/protocol-meta-item-reads.ts",
        "packages/metadata-protocol/src/protocol-meta-layered-reads.ts",
        "packages/metadata-protocol/src/protocol.lookup-artifact-item-call-sites.test.ts",
        "packages/metadata/package.json",
        "packages/metadata/src/metadata-manager-action-slots.test.ts",
        "packages/metadata/src/package-slotted-store.ts",
        "packages/metadata/src/serializers/typescript-serializer-annotation.test.ts",
        "packages/metadata/src/stored-item-package.ts",
        "packages/metadata/tsup.config.ts",
        "packages/rest/src/meta-qualified-item-route.test.ts",
        "packages/runtime/src/action-package-addressing.test.ts",
        "packages/runtime/src/domains/meta-qualified-item-read.test.ts"
      ],
      "shared_files": "Merged main 874166b6 (#32533): conflict only in metadata-manager-action-slots.test.ts (both append a describe), both kept; package-slotted-store.ts merged cleanly. protocol-meta-layered-reads.ts is shared with #32566 (seat 5); landing order is the seats' call.",
      "deviations": [
        "MetadataManager.get('action', NAME, P) answers P's own slot first (round 1, declared).",
        "The execution face keeps main's answer beside a package-less item (seat ruling B, declared).",
        "New public lean entry @objectstack/metadata/stored-item-package (storedItemPackageId, boundObjectOf; boundObjectOf was module-private), so the protocol reads the service's answer as the store does without loading the manager. Declared in the changeset and the PR body."
      ],
      "mcp_calls": "0 — GitHub reads via gh api REST GETs only",
      "api_writes": "Round 2: 2 relay issue_patch PR-body updates (run 43164924699, and the one carrying this head) and this report through post-stamped.mjs; plus git pushes (not REST).",
      "open_questions": [],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "filed: #32560 carries the 'held by N packages' wording with F4, F6(a), the service-only environment item and #32533 alignment."
      ]
    }

    Report taken 2026-11-12T09:21Z.


    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

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions