Skip to content

metadata: a draft save accepts an object name without the package namespace prefix; only publish-drafts refuses it (NAMESPACE_PREFIX) #27444

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcVkGJizGH7raJHhAvL

Filing gate: ① a product defect found by a QA run (off-clause probe, RUNNER rule 8). This is the same draft-vs-publish parity class as #26707.

Reproduction

  1. Boot the showcase and sign in as admin.
  2. POST /api/v1/packages with {"manifest":{"id":"qa.scratch.r2","name":"QA Scratch R2","version":"0.0.1","type":"app"}}. The resulting namespace is r2.
  3. PUT /api/v1/meta/object/qa_formula_pkg_r2?mode=draft&package=qa.scratch.r2 with a valid object body. The name has no r2_ prefix.
  4. Expected: the draft read's _diagnostics carries the NAMESPACE_PREFIX finding, as Studio/metadata: a draft the editors, the draft _diagnostics and the Problems tab all call valid is refused only at publish — and one such draft rolls back the whole package release #26707 made it carry the other publish rules.
  5. Actual: 200 state:"draft", and the diagnostics report valid. Then POST /api/v1/packages/qa.scratch.r2/publish-drafts answers outcome:"refused" with code NAMESPACE_PREFIX. The refusal rolls back the whole batch.

QA run R10 met the same thing: badprefix_thing was staged beside two valid drafts, and publish-drafts refused all three.

Mechanism

In packages/metadata-protocol's protocol.ts, the prefix check runs only when mode === 'publish' (~L20718, "a draft is judged when it is promoted"). objectNamespacePrefixViolation( is called at ~L20721, L22997 and L23766, none of which is the draft-verdict path that #26856 added (~L7181 / ~L10769).

Expected after fix

The draft verdict equals the publish verdict for the namespace-prefix rule, so Studio's Problems view names the bad object before publish.

QA-source: #27441 · api-backend.formula-stdlib-matrix · observed beside the clauses


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: studio | none | P①

    Triage: p2 · domain:server · area:devpath · 2026-10-29T08:09Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 29, 2026
  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    Claim: PM loop round 4
    Session: session_01L6bhgUCizoYWQVJWjhdR6F
    Account: os-sales
    Branch: claude/issue-27444-draft-verdict-package-prefix
    Worktree: objectstack-issue-27444
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/metadata-protocol/src/protocol-authoring-gate.ts (draftPublishVerdict), packages/metadata-protocol/src/protocol.ts (draft-verdict host wiring only), packages/metadata-protocol/src/protocol-save-door-refusals.ts (read; reuse objectNamespacePrefixViolation) and their tests (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: default (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: metadata-protocol draft verdict (this lane) | #26707 made the draft verdict carry the other publish rules | every Studio author whose draft object lacks the package namespace prefix
    Thread-read: 6491459162
    Premise: holds (read on main 481ade61 2026-10-29T21:53Z: objectNamespacePrefixViolation is called only at publish (protocol.ts:20688), promote (:23004) and the batch pre-flight (:23787); draftPublishVerdict (protocol-authoring-gate.ts:463) builds its verdict from judgeRuntimeAuthoringRules alone)
    Serial constraints cleared: #27670 (same protocol.ts) merged; no open PR edits these files.

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    os-dev-report
    {
    "issue": 27444,
    "status": "done",
    "branch": "claude/issue-27444-draft-verdict-package-prefix",
    "pr": "#27780",
    "head": "dda53adf",
    "session": "session_01L6bhgUCizoYWQVJWjhdR6F",
    "premise_still_valid": true,
    "summary": "Premise measured true on 481ade6: draftPublishVerdict built its verdict from judgeRuntimeAuthoringRules alone, so an unprefixed object draft read valid:true until publish-drafts refused the batch with NAMESPACE_PREFIX. draftPublishVerdict now asks the same judge, objectNamespacePrefixViolation (the host is handed the class's own method; one check, no copy), for an object draft on the draft row's package_id (the package publish-drafts promotes it under), and prepends one issue {rule: NAMESPACE_PREFIX, path: name, message: the judge's sentence} that withPublishVerdict folds into _diagnostics as valid:false. The draft save stays ungated (200 state:draft); publish refuses as before. Clause-2 no confirmed: only a read-side diagnostic is added, nothing accepted is refused.",
    "tests": "Red first: new case in packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts failed on main code (AssertionError: expected true to be false on diagnostics.valid; 1 failed | 16 passed). After fix: that file plus protocol.active-save-namespace-prefix and protocol.package-publish-audit-rows 43/43 passed. Full package pnpm --filter @objectstack/metadata-protocol test on dda53ad: Test Files 280 passed | 4 skipped (284), Tests 21804 passed | 26 skipped; VERDICT command-exit 0. Ablation via scripts/ablation-replace.mjs: call replaced with null, anchor 1->0, blob c477eabc961a->ad467a0d1c65, test red (1 failed | 16 passed), restored blob == HEAD c477eabc961a, git diff HEAD empty. The test imports ./protocol.js relatively from src, so no dist hop and no dist preflight applies.",
    "gates": "Local, on dda53ad (after one merge of origin/main): closure build pnpm --filter '@objectstack/metadata-protocol^...' build exit 0; pnpm --filter @objectstack/metadata-protocol typecheck exit 0; pnpm --filter @objectstack/metadata-protocol test exit 0; eslint --no-inline-config packages/metadata-protocol exit 0. dispatch-gates --commands: 61 derived, 60 exit 0. check:lean-entry-closure exited 3 first (objectql dist absent), exit 0 after building objectql. check:dual-build-cjs-loads exit 3, NOT MEASURED, PREREQUISITE NOT MET (needs every package's dist; CI Lint & Repo Gates runs it). --ran with exit codes: 61 derived, 60 run, 1 NOT-MEASURED, 0 UNRUN. merge-tree: none of the 16 open PRs touches the changed files. PR check-runs at report time: in_progress (Type Check, Lint, Check Changeset, Governed Surface Queue Guard and others); 3 opt-in jobs skipped.",
    "line_budget": "4 files, +92 / -2 (changeset 11, protocol-authoring-gate.ts +20/-2, protocol.ts +6, test +55)",
    "files_changed": [
    ".changeset/27444-draft-verdict-namespace-prefix.md",
    "packages/metadata-protocol/src/protocol-authoring-gate.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts"
    ],
    "deviations": [
    "protocol-save-door-refusals.ts was not edited (read only, as the claim says); the reuse goes through the existing protocol.ts wrapper.",
    "check:dual-build-cjs-loads NOT MEASURED locally (repo-wide dist prerequisite); left to CI.",
    "Report comment: the seat-signature line is line 1 (post-stamped.mjs refuses otherwise) and the os-dev-report marker is line 2, so the marker is not the comment's first line as os-dev.md words it."
    ],
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "0",
    "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, run 40970028511, opened #27780 draft, no assignees, no reviewers); this os-dev-report comment via scripts/pm/post-stamped.mjs (POST /repos//issues/27444/comments)",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed: the per-item publish skips sealed managed objects before the prefix judge and the draft verdict (like the batch pre-flight) does not; whether such a draft can exist was not measured. In PR Acceptance notes."
    ]
    }

  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

    ACCEPT → PR #27780 · head dda53adf · 2026-10-29T23:27Z · landing sent.

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain: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