Skip to content

console: every record page on a deployment without the approvals service logs two console errors for the designed 501 of GET /approvals/records/OBJECT/ID/lock (18.2.0 scaffold) #26632

Closed

Description

@objectstack-fleet

Filing gate: ① user-visible defect in the shipped console (@objectstack/console@18.2.0), reproduced at a public door, with a named location.

reach: the Console on a fresh 18.2.0 scaffold (npm create objectstack@18.2.0), measured on 3 loads plus a second scaffold.
QA-source: #26629 · smoke:npm-18.2.0 · F5
type: Bug

Reproduction (published 18.2.0)

  1. npm create objectstack@18.2.0 my-app; cd my-app; npx os dev -p PORT (SQLite; the scaffold composes no approvals service).
  2. Sign in at /_console/ as the seeded dev admin, open /_console/apps/com.objectstack.setup/my_app_note, click New and save. Or open an existing note's panel with ?recordId=ID.
  3. The browser console shows, on every open:
    • Failed to load resource: the server responded with a status of 501 (Not Implemented)
    • HTTP request failed: GET /api/v1/approvals/records/my_app_note/ID/lock -> 501 [NOT_IMPLEMENTED]
  4. Server side: GET /api/v1/approvals/requests?object=my_app_note&recordId=ID answers 200 {"data":[]}, and GET /api/v1/approvals/records/my_app_note/ID/lock answers 501 {"code":"NOT_IMPLEMENTED","message":"Approvals service is not configured on this deployment"}.

Expected: no console error. useRecordApprovals.ts (27f38ad) documents the 501 as the designed answer of "a composition without the approvals service" and treats it as "not locked". Actual: two error-level lines per record open. The record itself saves and reads back fine.

Because the requests door answers 200, the hook takes the service to be present and goes on to the lock read. The two doors disagree on whether the service exists.

Full evidence chain: the run record #26629, cell F5.

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p2 · domain:ui · area:workflow · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T12:00Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:workflowApprovals and automation — the work that runs without a person driving it
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 27, 2026
  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01J8VVAkHqAv2eFKVSt9LqkC
    Account: huangyiirene
    Branch: claude/project-thread-yltrjt
    Worktree: objectstack-issue-26632
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/app-shell/src/hooks/useRecordApprovals.ts and its tests (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the record page lock read logs the designed 501 through the client logger | the hook already fails open on 501; the log is the defect | every new user opening a record on a scaffold without the approvals service
    Thread-read: 6441358448
    Premise: holds
    Serial constraints cleared: none open; last change on the file #26666 (a71564f) is merged

    Dispatched to a card thread of the "objectstack ui" project (mode:thread); the dispatch order is the thread's opening message. The platform names the thread branch (claude/project-thread-yltrjt), not claude/issue-26632-approvals-lock-501. Read at 2026-10-27T13:04Z on origin/main f6ffd72347.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26632,
      "status": "done",
      "branch": "claude/project-thread-yltrjt",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26841",
      "session": "session_01J8VVAojjEQUUoMeSBSdgW4",
      "premise_still_valid": true,
      "head": "a0185cfb",
      "summary": "Measured producer: @objectstack/client fetch() logs every non-2xx via logger.error, and the console's createQuietHttpLogger (ui/packages/data-objectstack) prints it with console.error before the hook's fail-open catch runs; PM hypothesis held. Landing in the expected file surface: useRecordApprovals reads the lock through its own fetchJson (the transport the approvals list read already uses), latches a 501 in a module flag so no record asks again until reload, and logs every other failure through the same createQuietHttpLogger. The adapter gate on the lock read is kept (dropping it surfaced a wave-2 lock read in RecordDetailView.recordOpenWaves-13010). @objectstack/client is not changed. Card assignee not touched.",
      "tests": "head a0185cfb: cd ui && pnpm exec vitest run packages/app-shell/src/hooks/useRecordApprovals packages/app-shell/src/hooks/__tests__/useRecordApprovals packages/app-shell/src/views/RecordDetailView.recordOpenWaves-13010.test.tsx packages/app-shell/src/views/RecordDetailView.approvalLock packages/app-shell/src/views/RecordApprovalsPanel -> Test Files 15 passed (15), Tests 107 passed (107), lock VERDICT command-exit 0. pnpm --filter @object-ui/app-shell run type-check -> exit 0. Ablation (scripts/ablation-replace.mjs, anchor 'if (err?.status === 501) {' -> 999501, no build needed: app-shell's own suite reads src): the new 501 test went red (1 failed | 5 passed) on the 'HTTP request failed: ... /lock -> 501 [NOT_IMPLEMENTED]' line; restore blob == HEAD 975d85f2a294, git diff HEAD empty. Narrowed, declared: the full app-shell package run was stopped after ~40 min on the shared box (it found the waves-13010 regression, since fixed); CI Test UI owns the full run.",
      "gates": "dispatch-gates --commands: 34 derived; all 34 run locally, each exit 0 (type-check-debt re-run under the verify lock after a first queue-timeout exit 3 = NOT MEASURED, then exit 0: 126/129 type-checked, 0 DEBT). dispatch-gates --ran on the first record: 33 run, 1 UNRUN (type-check-debt), since run. node scripts/check-sdui-manifest.mjs exit 0. CI check-runs: in_progress at report time (seat owns convergence).",
      "line_budget": "218 changed lines (+167/-51), 3 files; under the 3000 human-merge threshold",
      "files_changed": [
        ".changeset/26632-record-lock-501-silent.md",
        "ui/packages/app-shell/src/hooks/useRecordApprovals.ts",
        "ui/packages/app-shell/src/views/RecordDetailView.approvalLock-25934.test.tsx"
      ],
      "deviations": [
        "Branch is the platform-named claude/project-thread-yltrjt, not claude/issue-26632-*, as the Claim records; worked in the container's own clone on that branch, not a git worktree.",
        "Lock test lives in views/RecordDetailView.approvalLock-25934.test.tsx (the hook's existing lock test), rewritten from the adapter SDK stub to the global fetch stub.",
        "Lock read no longer carries the SDK client's X-Environment-Id / Accept-Language headers; the sibling approvals list read never did, and the console adapter sets no environment id.",
        "Harness commit-attribution reminder named a model in Co-Authored-By; commits use the AGENTS.md model-free trailer pair instead."
      ],
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments); no write tool",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/26841/assignees, run 40558873139), relay comment (this report)",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: none (not filed) · the approvals list door answers 200 {data: []} without the service while the lock door answers 501 (packages/rest/src/approvals-routes.ts), so the browser's own network line for the first 501 still appears once per page load; making the doors agree is domain:server · carrier: #26632 (named in its body as the alternative) · noted in PR Acceptance notes, not filed"
      ]
    }

    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

area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:uiDomain 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