Skip to content

service-analytics: three fail-closed resolver faults answer 403 PERMISSION_DENIED, the same body as a real denial, where the platform answers a permission-store outage 503 SERVICE_UNAVAILABLE #25561

Closed

Description

@objectstack-fleet

Filing gate: ① a product defect with named locations (finding class (a): one closing card for the family; per-site rows below). Filed by domain:services seat 1 (seat post #6021) · os-sales · session session_016g7nYP9wdNx1GDa5XDr7Uy. ⛔ Not a claim.
Reader: the domain:server lane, packages/services/service-analytics, on the next PR that touches analytics admission refusals.
Dedupe (open AND closed): "analytics fail-closed resolver fault 403 PERMISSION_DENIED 503 SERVICE_UNAVAILABLE read admission field-level exposure unresolved". No hit (nearest: #25544 / PR #25560, where the consumer side of this was met).
reach: POST /api/v1/analytics/dataset/query and the cube query door. Measured by reading main b531016f6d; no live fault injected.
Source: the domain:server cli seat, while working #25544 (PR #25560).
type: Bug

What is wrong

Three of the analytics door's refusals are operator-side faults: a resolver threw, or could not answer. All three answer with the same wire body as a real denial: { code: 'PERMISSION_DENIED', status: 403, object }. A caller cannot tell "you may not read this" from "the server could not decide". A consumer that needs to tell them apart has to parse the English message.

site (main b531016f6d) what happened answer today
read-admission.ts assertObjectsReadable, catch branch (throw readAdmissionDeniedError(objectName) after "read-admission resolution failed … (fail-closed)") the object-level admission provider threw 403 PERMISSION_DENIED "reading X is not permitted for this user", byte-identical to the genuine denial two lines below
field-read-admission.ts fieldReadUnresolvedError the field-level read permissions could not be resolved 403 PERMISSION_DENIED
api-exposure-door.ts exposureUnresolvedError the API exposure declaration could not be read 403 PERMISSION_DENIED

Fail-closed is right: none of these may admit. The defect is only in what the refusal claims. Each one asserts a denial the server never reached.

The platform already ruled this class

packages/core/src/security/authz-store-unavailable.ts ends the same defect on the authz context. Its maintainer ruling of 2026-08-30 is quoted there verbatim: 「读失败 fail-loud —— 权限库不可达时不再解析为「已认证零能力」,而是响亮拒绝(与真实能力拒绝的 403 可区分),让宕机不再伪装成一次逐字节相同的能力否决。」

The spelling it chose is SERVICE_UNAVAILABLE / 503. That is an existing member of the closed ADR-0112 vocabulary (StandardErrorCode), mapped to 503 by HttpStatusErrorCodeMap. So the fix adds no new code and no new envelope key. The reason field or three new codes suggested at the source are not needed, and a field would be quiet by default, as that file's "Why a THROW, and not a field" section measures.

Expected

  • The three fault sites answer 503 SERVICE_UNAVAILABLE, naming the object and nothing else. The cause stays in the server log at the site, as today.
  • A real denial (assertObjectsReadable's !admitted branch, the field-level and exposure verdicts) keeps 403 PERMISSION_DENIED unchanged.
  • /analytics/dataset/query classifies a thrown error by code plus a 4xx status (analytics 的 filter 拒收到不了调用方:service 侧多数拒收没有 ADR-0112 信封,REST 面又用 message 正则嗅探,一律答 500 #5352). A 5xx must still render as that code, not fall through to 500 ANALYTICS_QUERY_FAILED. Pin that path.
  • The no-oracle rule in readAdmissionDeniedError's docblock still holds. A 503 names no layer, grant or existence fact. It says only that the server could not decide.

Notes for the dispatcher


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    domain:serverDomain lane — seat card indexed by label:pm:seat
    and removed on Oct 24, 2026
  2. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop · domain:cli seat 1 · p2 · 2026-10-24T01:36Z
    Session: session_01CxBKycaiUpA1yGx1XyoGqX
    Account: os-sales (the seat's linked user; always the card's assignee)
    Branch: claude/issue-25561-analytics-fault-503
    Worktree: objectstack-issue-25561
    Domain: domain:server (assigned to this seat by the coordinator, 2026-10-24T01:34Z, after the services seat filed it from this seat's #25544 finding)
    Seat: domain:cli#1 (seat post #6024; 由Sales账户的项目负责)
    File surface (read on origin/main ce18e73483; stop on a breach): packages/services/service-analytics/src/read-admission.ts (the assertObjectsReadable catch branch), field-read-admission.ts (fieldReadUnresolvedError), api-exposure-door.ts (exposureUnresolvedError), their tests under service-analytics/src/__tests__/, the /analytics/dataset/query relay pin (read in packages/rest, a test only if the 5xx path is unpinned), packages/metadata-protocol/src/build-probes.ts + its widget-refusal test (the PR #25560 consumer: a SERVICE_UNAVAILABLE refusal must not fall to the dataset fix), one changeset.
    Container & model: S, mode:subagent, model: default tier
    Clause-②: no
    Basis for the Clause-② line: three fault-path refusals keep refusing and change only their code and status (403 PERMISSION_DENIED → 503 SERVICE_UNAVAILABLE, an existing ADR-0112 member); no request shape that was served is refused. A wire change, so the title takes ! and the changeset a BREAKING banner; the arm is re-read against AGENTS.md on the measured diff.
    Responsibility: n/a — filed by domain:services seat 1 from #25544's dev report.
    Thread-read: none
    Serial constraints cleared: none of the 12 open PRs touches service-analytics or build-probes.ts (file lists read in this act).


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25561,
      "status": "done",
      "branch": "claude/issue-25561-analytics-fault-503",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25595",
      "session": "session_01CxBKycaiUpA1yGx1XyoGqX",
      "premise_still_valid": true,
      "summary": "The three operator-side FAULT refusals in service-analytics now answer 503 SERVICE_UNAVAILABLE instead of the denial's 403 PERMISSION_DENIED: the read-admission catch branch (provider threw), the field-level reader throw, and the exposure-declaration lookup throw. All three go through one shared non-exported constructor, readAdmissionUnresolvedError in read-admission.ts. It follows the core authz-store-unavailable precedent ({code, status, object}), names only the object, and leaves the cause in the site log. Fail-closed is unchanged, and real denials (the !admitted branch, the field verdicts, exposure 404/405) are byte-unchanged. The dataset door already relays a declared 5xx through declaredServerFaultAnswer, so packages/rest has no source change; a new rest seam test pins producer plus route. build-probes.ts gives a SERVICE_UNAVAILABLE throw its own server-side-fault fix. Changeset: patch on @objectstack/service-analytics and @objectstack/metadata-protocol, BREAKING banner, Clause-② no, Metadata-protocol none, ADR-0087 not-required.",
      "tests": "Tree sha 18b8b6fa5d (service-analytics and metadata-protocol files byte-identical to their state at each full run). service-analytics vitest (whole pkg): Test Files 185 passed (185), Tests 4517 passed | 262 skipped. The first run with the fix had 10 failed / 4503 passed: exactly the 10 fault-leg pins asserting 403, now moved to 503 in read-admission-gate, field-read-admission-gate, field-query-admission-gate, api-exposure-door and unexposed-definition-registration. metadata-protocol (whole pkg): Test Files 263 passed | 3 skipped, Tests 21472 passed | 19 skipped. build-probes-widget-refusal-fix.test.ts is 8/8 on 18b8b6fa5d (2 new SERVICE_UNAVAILABLE cases). rest src/analytics*: Test Files 23 passed, Tests 298 passed | 22 skipped. New rest analytics-read-gate-fault-envelope.test.ts is 7/7 on 18b8b6fa5d: 3 faults are 503, their twins are 403/403/404, plus a 200 control. runtime http-dispatcher + packages-publish-drafts-probe-caller-context: 251 passed. typecheck exit 0 for service-analytics, metadata-protocol and rest. Ablation (fix committed first): ablation-replace.mjs reverted the read-admission catch to throw readAdmissionDeniedError plus a marker (anchor 1 to 0, blob 323b9767 to 83a362db); service-analytics rebuilt; ablation-dist-preflight showed the marker present in dist/index.js and dist/index.cjs (exit 0). read-admission-gate.test.ts: 6 failed | 19 passed (the fault case on 3 doors x 2 strategies). rest seam: 1 failed | 6 passed (the object-level fault row). Restore: blob == HEAD 323b9767, git diff HEAD empty; after the rebuild, preflight --absent reported the marker absent from 6 built files, the tree clean, and the rest seam 7/7.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 72 commands. All 72 were run locally; `--ran` reconciliation: 'Run reconciliation - 72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero: all 72 exit-coded, none 3). Final exits are all 0. The first pass had red: check-rest-log-spy-declared exit 1 (the new rest test spied console.error without OS_REST_LOG; fixed in this PR, re-run exit 0). check:dts-closure exit 1, check:dual-build-cjs-loads exit 3 PREREQUISITE and check:type-check-debt exit 3 were tree state from a concurrent closure build rewriting dist/; re-run on the settled tree, all exit 0. pnpm lint via os-verify-lock: 'VERDICT command-exit 0'. CI on PR #25595 head 18b8b6fa5d at report time: 38 check-runs, 6 success, 7 skipped, 25 queued/in_progress (Build Core queued, Governed Surface Queue Guard in_progress) - in_progress.",
      "line_budget": "Size S dispatched; measured 472 changed lines (+404 / -68) in 12 files per dispatch-gates. Source: read-admission.ts, field-read-admission.ts, api-exposure-door.ts and build-probes.ts. Tests: 5 analytics test files, 1 new rest test file, 1 metadata-protocol test. Plus 1 changeset. Most of the growth is docblocks and the new rest seam test.",
      "files_changed": [
        ".changeset/25561-analytics-read-gate-fault-503.md",
        "packages/metadata-protocol/src/build-probes-widget-refusal-fix.test.ts",
        "packages/metadata-protocol/src/build-probes.ts",
        "packages/rest/src/analytics-read-gate-fault-envelope.test.ts",
        "packages/services/service-analytics/src/__tests__/api-exposure-door.test.ts",
        "packages/services/service-analytics/src/__tests__/field-query-admission-gate.test.ts",
        "packages/services/service-analytics/src/__tests__/field-read-admission-gate.test.ts",
        "packages/services/service-analytics/src/__tests__/read-admission-gate.test.ts",
        "packages/services/service-analytics/src/__tests__/unexposed-definition-registration.test.ts",
        "packages/services/service-analytics/src/api-exposure-door.ts",
        "packages/services/service-analytics/src/field-read-admission.ts",
        "packages/services/service-analytics/src/read-admission.ts"
      ],
      "deviations": [
        "PR body footer: ends with the AGENTS.md / role-file session-URL footer form (rule line, then a single _Generated by [Claude Code](https://claude.ai/code/session_01CxBKycaiUpA1yGx1XyoGqX)_ line), not the dispatch's robot-emoji 'Generated with' line. The role file wins on conflict, and two footers are what AGENTS.md warns against.",
        "PR body line order: the dispatch's two attribution lines come first, so 'Fixes #25561' is on line 4, not line 1 as the role file says. The attribution line is an HTML-comment shape, which the role file bans in GitHub text. It was kept because the repo's own recognisers (record-recognisers.mjs, check-governed-queue-guard.mjs) read exactly that line; the relay read-back reports the body stored byte-identical, 8848 of 8848 bytes.",
        "Added one packages/rest TEST (no rest source change). The route relay was already pinned for a hand-built declared 503, but the producer-plus-route seam with a real AnalyticsService was not; the dispatch asks to pin the 503 through the real route.",
        "Removed the two non-exported per-file constructors (fieldReadUnresolvedError, exposureUnresolvedError) in favour of one shared readAdmissionUnresolvedError, so the 503 names no layer (the dispatch's no-oracle rule). No package export changed.",
        "Cube query door (/api/v1/analytics/query, runtime dispatcher-plugin errorResponseBase): read, not pinned; it relays declared status and code generically. A runtime test is outside the file surface."
      ],
      "dogfood_battery": "18b8b6fa5d · os-verify-lock 'VERDICT command-exit 0' (pnpm --filter @objectstack/dogfood test after the @objectstack/dogfood^... closure build, no OS_TEST_SHARD, no path) · Test Files 291 passed | 3 skipped (294) · Tests 2505 passed | 18 skipped (2523) · no failures",
      "mcp_calls": "0 - no MCP GitHub calls",
      "api_writes": "2 relay strokes via scripts/pm/ write tools: (1) fleet-write pr_create: POST /repos/objectstack-ai/objectstack/dispatches, executed by the relay as POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/25595/assignees [os-sales], run 40057862663 success; (2) post-stamped os-dev-report comment: POST /repos/objectstack-ai/objectstack/issues/25561/comments. git push (several pushes to the branch) is not a REST write.",
      "open_questions": [
        {
          "question": "Should the object-level plugin bridge's UNUSABLE branch (plugin.ts admitObjectRead auto-bridge: the security service lookup threw, or the service exposes neither canReadObject nor explain, which also covers a deployment with no security service on the in-repo kernels) also answer 503 instead of returning false and getting 403?",
          "options": [
            "A: throw from the UNUSABLE branch so assertObjectsReadable answers 503. This moves the pinned admission-bridge-resolution.test.ts 403 cases and touches the #22235 ruling's refusal (code unspelled there).",
            "B: keep 403. The #22235 ruling frames a deployment with no security service as a declared refusal, not an outage."
          ],
          "recommendation": "A for a registered-but-broken service (same class as this card); ask the maintainer whether the never-registered case under the #22235 ruling also moves, since that ruling is the authority there."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: named producer: service-analytics plugin.ts admitObjectRead auto-bridge UNUSABLE branch returns false, so POST /api/v1/analytics/dataset/query answers 403 PERMISSION_DENIED for a security service that could not be resolved, a fault that reads as a denial. Pinned at 403 on main by admission-bridge-resolution.test.ts ('DENIES when resolving the security service THROWS', 'DENIES when the security service exposes neither canReadObject nor explain', and the dataset-query case). The same family as #25561, outside its file surface; not fixed here. dedupe words: analytics admitObjectRead bridge unusable security service 403 PERMISSION_DENIED 503 SERVICE_UNAVAILABLE fault"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25595 comment 6382488582 · domain:cli seat 1 · session session_01CxBKycaiUpA1yGx1XyoGqX · 2026-10-24T09:22Z


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:cli seat 1 · session session_01CxBKycaiUpA1yGx1XyoGqX · 2026-10-24T10:14Z

    reading result
    PR #25595 object merged: true, merge commit f1d6be029e, merged 2026-10-24T10:14:21Z through the merge queue
    origin/main f1d6be029e is an ancestor of origin/main, single parent (squash)
    queue branch no gh-readonly-queue/main/* head for PR 25595 remains

    State: card closed completed by the PR's Fixes #25561. pm:dispatched stripped in this act. The plugin bridge's UNUSABLE branch (still 403, the #22235 ruled answer) is outside this card and stays with the maintainer's ruling; nothing about it is decided here.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: needs_decision fork (PR #25595 dev report 6379262084, open_questions[0]) · letter A · maintainer 「25561 同意」 · recorded by domain:cli seat 1 (seat post #6024) · session session_01CxBKycaiUpA1yGx1XyoGqX · 2026-10-24T13:18Z

    The maintainer (Sales) ruled in the project's ruling thread, on the decision card that recommended A. This is a maintainer ruling, not an auto-adjudication.

    The question

    packages/services/service-analytics/src/plugin.ts, the auto-bridged admitObjectRead: its UNUSABLE branch (resolving the security service threw, or the service exposes neither canReadObject nor explain) answers return false, so the caller gets 403 PERMISSION_DENIED, the same bytes as a real denial. On the in-repo kernels (ObjectKernel, LiteKernel) a security service that was never registered lands in the same branch, because their synchronous getService throws on a miss. PR #25595 moved the three other analytics fault paths to 503 SERVICE_UNAVAILABLE.

    • A (ruled): the UNUSABLE branch throws, so the gate answers 503 SERVICE_UNAVAILABLE for both a registered-but-broken service and a never-registered one.
    • B: keep 403.
    • C: split them (broken 503, never-registered 403). That needs packages/core to brand the synchronous getService miss, or a message match.

    Why A

    Execution (decided once)

    1. plugin.ts: the UNUSABLE branch of the object-level bridge throws a declared 503 SERVICE_UNAVAILABLE (readAdmissionUnresolvedError) instead of return false. The query is still refused before any read.
    2. Correct the false operator log line "A security service is wired on this deployment": it is also printed when no security service was ever registered.
    3. admission-bridge-resolution.test.ts: the three UNUSABLE 403 pins become 503. The real denials (canReadObject / explain answering false) stay 403.
    4. ! title, @objectstack/service-analytics patch changeset with a BREAKING banner (a status on the wire moves), as PR fix(service-analytics)!: an analytics read gate that could not decide answers 503 SERVICE_UNAVAILABLE, not the denial's 403 #25595.
    5. A dated note on finding(service-analytics, core): with no security service ever registered, every analytics query is refused 403 on the in-repo kernels, while the declared contract and the released text say an absent security service admits #22235: the code moves 403 → 503, the denial does not, by this ruling.
    6. Out of scope: the ABSENT branch (a context that answers the lookup with nothing admits and warns once) stays unruled.

    Executor: domain:cli seat 1, one PR, S.

    os-decision-facets
    ① 长远:#25595 已立「故障不冒充拒绝」,A 让分析门四处一致;spec 对 SERVICE_UNAVAILABLE 的定义含「not loaded」,无需 C 的新区分。
    ② 拉动:坏掉场景即 #25561 的运维故障类;从未注册的部署无实测;消费端已按 code 分流。
    ③ 防错:B 让按 code 分流的消费端把宕机当无权;C 若按消息判别是反模式;A 与 core 先例同形。
    ④ 不扩散:A 复用现有码,不加键、不加门;B 零;C 动 core。
    Prior rulings read: admitObjectRead,SERVICE_UNAVAILABLE,security-service,PERMISSION_DENIED,fault-as-refusal,admission-bridge,degrade,fail-closed → 23 hits; ADR-0056 D2; none on the code; thread: #22235 6056384408/6056824332


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: the ruling-A follow-up (6384696061) · session session_01CxBKycaiUpA1yGx1XyoGqX (domain:cli seat 1, seat post #6024) · because the maintainer voided that seat · to domain:server seat 1 (seat post #6367), same account

    • Provenance: who — the maintainer (Sales); what, verbatim — 「cli 席位作废」 as relayed in the Sales account's project at 2026-10-24T13:22Z; that project then summoned domain:server seat 1 (verbatim: 「开」) to carry the in-hand server work.
    • Handover record: nothing was pushed for the follow-up; the voided session stopped with a local work-in-progress commit (the bridge's UNUSABLE branch throws, the false log line fixed, one test file's 403 pins moved to 503). Still open: the 403 pins in the other two test files, the changeset, and the test runs. The card's PR fix(service-analytics)!: an analytics read gate that could not decide answers 503 SERVICE_UNAVAILABLE, not the denial's 403 #25595 landed earlier (f1d6be029e); this card stays closed.

    Claim: ruling-A follow-up (one PR, Refs #25561, not Fixes) · domain:server seat 1 (seat post #6367, project run by the Sales account, 由Sales账户的项目负责) · p2 · 2026-10-24T13:34Z
    Session: session_01JrXUZYyTV4i588KLZRxSvJ
    Account: os-sales (the seat's linked user; the card's assignee)
    Branch: claude/issue-25561-bridge-503
    Worktree: objectstack-issue-25561
    Domain: domain:server
    Seat: domain:server#1
    File surface: packages/services/service-analytics/src/plugin.ts (the auto-bridged admitObjectRead UNUSABLE branch throws SERVICE_UNAVAILABLE/503 for a registered-but-broken and a never-registered security service; the untrue "A security service is wired…" log line corrected), src/read-admission.ts if the shared constructor needs it, the service-analytics tests that pin that branch's 403, any packages/rest seam pin of the same, and a patch changeset on @objectstack/service-analytics. After it lands, a dated note on #22235.
    Container & model: M, mode:subagent (general-purpose subagent loading .claude/agents/os-dev.md as its role file), model: default tier (dispatch-gates.mjs --tier: "no path-derived mandate"), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: service-analytics' own bridge produces the 403-for-a-fault; the platform answers a permission-store outage 503 (authz-store-unavailable), which PR #25595 already followed for the three other analytics fault paths; reached by any deployment whose security service is missing or broken.
    Thread-read: 6384696061
    Serial constraints cleared: no open PR touches packages/services/service-analytics/src/plugin.ts (read this act).
    Resume-from: none (no pushed branch)


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment (Premise: line, read before dispatch) · domain:server seat 1 (seat post #6367) · session session_01JrXUZYyTV4i588KLZRxSvJ · 2026-10-24T13:43Z
    Premise: holds, read by a read-only subagent on origin/main baae6ed1. packages/services/service-analytics/src/plugin.ts's auto-bridged admitObjectRead still answers its UNUSABLE branch with return false (so the caller's readAdmissionDeniedError, 403), after an error log whose text claims a security service is wired, which is untrue for the never-registered case. readAdmissionUnresolvedError (503 SERVICE_UNAVAILABLE, from PR #25595) exists in src/read-admission.ts to reuse. The 403 pins of that branch are in src/__tests__/admission-bridge-resolution.test.ts (three cases) and src/__tests__/admission-absence-report.test.ts (one case); none under packages/rest. No open PR touches service-analytics.
    Dispatch: one in-seat subagent dev (general-purpose loading .claude/agents/os-dev.md); PR says Refs #25561.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 25561,
    "status": "done",
    "branch": "claude/issue-25561-bridge-503",
    "pr": "#25673",
    "session": "session_01JrXUZYyTV4i588KLZRxSvJ (mode:subagent, the PM session's id; run as a general-purpose agent loading .claude/agents/os-dev.md as its role file)",
    "premise_still_valid": true,
    "summary": "Ruling A (6384696061) is implemented as one draft PR, #25673, which says Refs #25561. In service-analytics plugin.ts, the auto-bridged admitObjectRead's UNUSABLE branch now throws readAdmissionUnresolvedError(object) instead of return false, so the gate answers 503 SERVICE_UNAVAILABLE naming the object. That covers a broken security service, one that exposes neither canReadObject nor explain, and one never registered on ObjectKernel or LiteKernel. Fail-closed is unchanged, and real false verdicts stay 403, byte-unchanged. The untrue error log sentence (A security service is wired on this deployment) is corrected in the object-level bridge, and also in the row-scope bridge in the same file, which printed the same false sentence for the same two cases; that bridge's answer does not change. Doc comments that called the never-registered answer a denial are respelled (plugin.ts, read-admission.ts, analytics-service.ts, scripts/analytics-reconcile/boot.ts). No docs/adr edit was needed. The changeset is a service-analytics patch with a BREAKING banner. The voided session's WIP patch was applied as-is and then finished. Its comment lines were rewrapped and its row-scope log fix kept. A fifth pin the premise read did not list was found by the whole-package run and moved: read-scope-bridge-resolution.test.ts, both auto-bridges live, throwing resolver. Deviation from the dispatch text: commits carry the model-free trailer pair (Claude-Session plus Co-authored-by: Claude), not the model-named Co-Authored-By line the dispatch asked for, because AGENTS.md and os-dev.md forbid a model identifier in that pair and os-dev.md wins over a dispatch on conflict.",
    "tests": "Head 032ae18 (= 2489588 plus a merge of origin/main #25658, which touches only .claude/skills/pm-dispatch/references and scripts/pm/check-half-states.mjs; the service-analytics tree is byte-identical). pnpm --filter @objectstack/service-analytics test at 2489588: VERDICT command-exit 0, Test Files 185 passed (185), Tests 4517 passed, 262 skipped (4779). The first run, before the row-scope pin moved, was red on exactly that pin (1 failed, 184 passed). typecheck: VERDICT command-exit 0. eslint --no-inline-config on the 7 changed source files: exit 0. Dogfood battery at 032ae18 (owed by the bang title): closure build command-exit 0; pnpm --filter @objectstack/dogfood test VERDICT command-exit 0, Test Files 293 passed, 3 skipped (296), Tests 2509 passed, 18 skipped (2527).",
    "gates": "dispatch-gates --commands at 032ae18 derived 82 commands; all 82 run, each recorded as cmd :: exit N, all exit 0. --ran verdict: 82 derived famil(ies) accounted for, 82 run, 0 NOT-MEASURED (a DERIVED zero; all 82 recorded an exit code and none of them is 3). Earlier run at 2489588: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, no dist) and check-plugin-teardown-shape --self-test exit 3 (pinned fixture commit unreachable on the shallow clone). Both exit 0 at the final head, after the dogfood closure build and a single-commit fetch of the fixture. CI on PR 25673 at report time: Auto Label, filter, Check PR Size, Check Documentation Links, the claim and closing-keyword guards success; Test Core 1-6, Build Core, Lint lanes, Type Check lanes, Check Changeset, Governed Surface Queue Guard, Dogfood Regression Gate in_progress.",
    "ablation": "On the committed fix, via scripts/ablation-replace.mjs: anchor throw readAdmissionUnresolvedError(object); replaced by return false; (anchor x1 to x0, blob 83715b24c049 to 0e7c50c8c5b1). The subject resolves from source (tests import ../plugin.js), so there is no dist leg. Red: Test Files 3 failed (3), Tests 6 failed, 12 passed (18). Every changed negative pin failed with Expected code SERVICE_UNAVAILABLE / status 503, Received code PERMISSION_DENIED / status 403. The failing pins were: the throw case, the neither-method case, the ObjectKernel and LiteKernel never-registered cases, the absence-report real-kernel case, and the row-scope both-bridges-live case. The 12 that stayed green include every real-denial 403 pin. Restore: blob after restore 83715b24c049 == HEAD, git diff HEAD empty. Green rerun: Test Files 3 passed (3), Tests 18 passed (18).",
    "dogfood_battery": "032ae18225 · os-verify-lock VERDICT command-exit 0 · Test Files 293 passed, 3 skipped (296) · Tests 2509 passed, 18 skipped (2527) · no failures",
    "relay_writes": "3, all through scripts/pm: fleet-write pr_create (draft, assignees os-sales; read back as 7790 bytes sent, 7790 stored, identical, assignees os-sales), fleet-write pr_request_reviewers os-sales on 25673 (run success; read back as requested_reviewers os-sales), and post-stamped os-dev-report comment on 25561",
    "api_writes": "0 outside the relay and post-stamped; git push to claude/issue-25561-bridge-503 (empty-branch probe plus 3 pushes) is not a REST write",
    "mcp_calls": "0. No MCP GitHub tool was called, read or write.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted in PR Acceptance notes, not filed · the bridge's refusal now logs two error lines per query (the bridge's own line carrying the cause, plus assertObjectsReadable's catch line), the same catch line every throwing provider already gets"
    ]
    }

  10. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25673 comment 6385890367 · domain:server seat 1 (seat post #6367) · session session_01JrXUZYyTV4i588KLZRxSvJ


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed (ruling-A follow-up 6384696061) · domain:server seat 1 (seat post #6367) · session session_01JrXUZYyTV4i588KLZRxSvJ · 2026-10-24T15:57Z

    reading result
    PR #25673 object merged: true, merge commit 2e6d446bad, merged 2026-10-24T15:56:48Z through the merge queue
    origin/main 2e6d446bad is an ancestor of origin/main, single parent (squash)
    queue branch no gh-readonly-queue/main/* head for PR 25673 remains

    State: the card stays closed (PR #25595 closed it; this PR was Refs #25561). The follow-up is done and the seat's hold on it ends with this note. A dated note goes on #22235, whose ruled answer this changes.


    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:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething 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