Skip to content

Error-code ledger provenance: INVALID_METADATA now has a second emitter (@objectstack/plugin-security) and is registered under only one #7504

Description

@os-zhuang

Observation filed while implementing #7474. The dispatch for that card put packages/spec out of surface (the error vocabulary belongs to the spec seat), so this is recorded rather than done.

What changed

The #7474 PR makes @objectstack/plugin-security emit INVALID_METADATA (422) for the controlled_by_parent-without-master_detail authoring defect. The code is drawn from the existing closed vocabulary deliberately — ADR-0112's registration guidance says a generic condition takes an existing entry rather than a registered synonym, and "your metadata is broken" is exactly what INVALID_METADATA already names on the metadata-protocol publish path.

The gap

Nothing on the wire is wrong: ERROR_CODE_LEDGER dedupes into REGISTERED_ERROR_CODES, so INVALID_METADATA is already a member of the ErrorCode union and every envelope conformance parse passes. What is now incomplete is the ledger's provenance, which the file itself defines as per-emitter:

A code emitted by several packages is listed once per emitting package — the union dedupes; the per-package rows are provenance, not identity.

INVALID_METADATA sits under '@objectstack/metadata-protocol' only. It should also sit under '@objectstack/plugin-security'.

Why it is worth a row rather than nothing

The ledger's retirement rule reads the rows as the emitter list: "A row whose last EMITTER is deleted comes out with it." With provenance missing, a future retirement pass on metadata-protocol's INVALID_METADATA would look correct and would unregister a code plugin-security still throws — the silent fourth state, arrived at by following the documented procedure.

No behaviour change, no gate red today: check:error-code-casing checks casing, and error-code-ledger.test.ts checks casing, duplication and shadowing — none of them checks which package emits what.

The change

One line in packages/spec/src/api/error-code-ledger.zod.ts:

  '@objectstack/plugin-security': [
    'INVALID_METADATA',           // controlled_by_parent declared with no master_detail relation (#7474)
    'SUGGESTION_NOT_FOUND',
    'SUGGESTION_STATE',
  ],

Activity

  1. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    ContributorAuthor

    Routing repair only: appended domain:spec-surface — the finding grade is unchanged and no ownership is taken.

    • Landing anchor (read @ origin/main 1530870): packages/spec/src/api/error-code-ledger.zod.ts:261 (INVALID_METADATA under @objectstack/metadata-protocol only) and :366 (the @objectstack/plugin-security row, currently SUGGESTION_* only) — the missing provenance row is exactly as filed. The second emitter is already live on main (packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts:618 asserts the 422), so the gap is current, not pending a PR.
    • Domain judgment: the one-line row is validation-invariant — ERROR_CODE_LEDGER dedupes into the union, so every input keeps its byte-identical verdict; provenance rows are ledger bookkeeping, not acceptance. Same-judgment ⇒ domain:spec-surface (natural sweep-pack candidate for that seat's next batch).

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 11, 2026

    @os-zhuang
    ContributorAuthor

    Findings triage round, 2026-08-11 (PM session, maintainer-directed: 「跑一轮集中定级」).

    Graded: promote. Ledger provenance is part of the error-code contract's self-description: INVALID_METADATA now has a second emitter and the ledger row names one. S — a provenance row update, no wire change; sweep-eligible with the spec-surface lane's next batch.

    finding → pm:queue (domain:spec-surface).


    Generated by Claude Code

  3. self-assigned this
    on Aug 12, 2026
  4. os-zhuang commented on Aug 12, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 1 (spec-surface seat, shift of 2026-08-12)
    Session: session_016YBUGvukaeVu9DjKdsHJa9
    Branch: claude/issue-7504-ledger-provenance
    Worktree: objectstack-issue-7504
    Domain: domain:spec-surface
    File surface: packages/spec/src/api/error-code-ledger.zod.ts — the @objectstack/plugin-security provenance block (~L381) plus its comment
    Container & model: S mechanical, mode:subagent, model: sonnet
    Serial constraints cleared: no open PR touches this file. Noted: PR #7829 (spec,plugin-security) is in flight on adjacent territory — if it turns out to add ledger rows, the standard pre-PR merge origin/main covers it. Premise re-verified on origin/main @ 0dcbc11: INVALID_METADATA sits under @objectstack/metadata-protocol only (L275); the plugin-security block (L381) lacks it; the second emitter is already live on main (triage's anchor, plugin-security 422 test).


    Generated by Claude Code

  5. os-zhuang commented on Aug 12, 2026

    @os-zhuang
    ContributorAuthor

    os-dev-report

    {
      "issue": 7504,
      "status": "done",
      "branch": "claude/issue-7504-ledger-provenance",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/7873",
      "premise_still_valid": true,
      "summary": "Added the missing @objectstack/plugin-security provenance row for INVALID_METADATA in packages/spec/src/api/error-code-ledger.zod.ts, with a comment explaining the second-emitter relationship to @objectstack/metadata-protocol and referencing #7474/#7504. Placed alphabetically before SUGGESTION_NOT_FOUND/SUGGESTION_STATE, matching the file's existing per-block alphabetical convention (verified across all 23 ledger blocks). Pure ledger bookkeeping: no wire/behavior change, since ERROR_CODE_LEDGER already deduped INVALID_METADATA into the ErrorCode union via metadata-protocol.",
      "tests": "pnpm --filter @objectstack/spec build -> green (tsup + DTS build succeeded). pnpm --filter @objectstack/spec typecheck -> green (tsc --noEmit, check:scripts-typecheck, check:test-typecheck all passed). pnpm check:error-code-casing -> '17 self-test cases pass' + 'no lowercase error codes in 3682 scanned file(s)'. pnpm check:nul-bytes -> '75 self-test assertions' + 'scanned 7206 text file(s) ... no raw ASCII control bytes'. pnpm --filter @objectstack/spec exec vitest run error-code-ledger -> 'Test Files 1 passed (1), Tests 8 passed (8)'. pnpm --filter @objectstack/spec check:docs -> '230 generated files in sync with packages/spec' (no diff) -- measured that content/docs/references/api/error-code-ledger.mdx lists only the deduped ErrorCode union's allowed values (INVALID_METADATA was already present via the first emitter), not per-package provenance rows, so this change reaches no doc consumer. CI's Build Docs job on the PR head commit came back 'completed / skipped', corroborating the measurement. No changeset added; applied skip-changeset label myself (read back as ['size/xs','skip-changeset'] via GET /repos/.../pulls/7873 after the write settled).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. os-zhuang commented on Aug 12, 2026

    @os-zhuang
    ContributorAuthor

    ACCEPT (PM review, session session_016YBUGvukaeVu9DjKdsHJa9) — PR #7873.

    Landing: ready-flip + auto-merge once the ESLint and TypeScript Type Check jobs conclude success (flip checkpoint armed; the PM owns convergence).


    Generated by Claude Code

  7. added 2 commits that reference this issue on Aug 17, 2026
    fb76aa7
    09a9a8a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions