Repository navigation
fix(plugin-webhooks): gate webhook redelivery on webhook-administration access - #27474
Conversation
WIP: the redeliver door asks the security service, before the body is read, whether the signed-in caller may administer webhooks. Claude-Session: https://claude.ai/code/session_017xRBcSwDXZrZg7nGjP6P3U Co-authored-by: Claude <noreply@anthropic.com>
…he HTTP layer Both faces: an administrator replays; a signed-in caller not entitled is refused 403 with one answer whatever the request names; no security service or a throwing decision refuses 503. Existing door suites register a security double that admits their callers. Claude-Session: https://claude.ai/code/session_017xRBcSwDXZrZg7nGjP6P3U Co-authored-by: Claude <noreply@anthropic.com>
…te, in docs, checklist and changeset Claude-Session: https://claude.ai/code/session_017xRBcSwDXZrZg7nGjP6P3U Co-authored-by: Claude <noreply@anthropic.com>
…e in the pinned ledger Claude-Session: https://claude.ai/code/session_017xRBcSwDXZrZg7nGjP6P3U Co-authored-by: Claude <noreply@anthropic.com>
…the alignment it is Claude-Session: https://claude.ai/code/session_017xRBcSwDXZrZg7nGjP6P3U Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 47 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 14 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 7 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1ab02816399185c40801f5733f43c0dc5d5392d5 && git checkout 1ab02816399185c40801f5733f43c0dc5d5392d5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 57c51aab4d2f63293676e9412daed8a5fc54c1bc b4a2146cb6c24b77a6a5244274195b2067e295b1 && git checkout -B drift-repro 57c51aab4d2f63293676e9412daed8a5fc54c1bc && git merge --no-ff b4a2146cb6c24b77a6a5244274195b2067e295b1
node scripts/docs-audit/affected-docs.mjs --json 57c51aab4d2f63293676e9412daed8a5fc54c1bc
|
|
domain:devx#1 · sunhaolin · session_017xRBcSwDXZrZg7nGjP6P3U Contract reviewServed-tier: Inputs: PR #27474 body and file list, the net diff against ① Derived judgmentsEach accept-set or public-surface change the diff implies, named right or wrong against the cited code:
② Semver level
③ Boundary flags
④ Design judgmentJudged against the cited code on Must-fix (FAIL):
Should-fix:
Held (no finding): the identity judged is the session the door already read ( Implemented-by: VERDICT: FAIL |
…h the tenancy posture, and scope the replay to it The entitlement gate now hands the request-context composition the door's own way to reach the tenancy service, so the session's organization claim is vetted against the posture in force exactly as it is on the data API (the per-request membership check of the 2026-09-05 ruling, option B). The admission carries the vetted tenantId and the replay is scoped to it, never to the raw session claim; a claim the composition did not keep is refused with the same caller-level answer, since the replay would have no organization to be scoped to. The plugin also says once at kernel:ready when the door is served with no security service to decide, naming the remedy, instead of leaving the 503 to be discovered per request. Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
… retire stale posture text; declare the narrowing The entitlement suite gains the walled-posture cases (an organization claim no current membership backs is refused with the caller-level answer and nothing is replayed, on isolated and group; a backed claim is admitted and the replay is scoped to that organization), the once-at-boot line for a kernel with no security service, and the door's tenancy resolver on a real ObjectKernel registry (never registered reads as no posture; registered and failing is the 503). The security double records the organization the caller's context was resolved in. Three stale "any authenticated user" posture statements are retired: the two messaging outbox docblocks and the platform checklist clause's verify field (r13, with its step driving the redeliver as the seeded admin). The changeset declares the narrowing (Clause-② no (narrowing), BREAKING banner, one ADR-0087 disposition); the level stays patch. ADR-0124 D1 gains an anchor for redeliver-entitlement.ts, and the docs page states the organization vetting. Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
…s the caller's bound Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk Ruled: maintainer, in the PM session session_017xRBcVy4VXmkQjn2MGeaWk, 2026-10-29 · 2026-10-29T13:05Z Question (human floor, from the contract review): which permission axis gates webhook redelivery. Answer, verbatim option chosen: 「sys_webhook 的编辑权限」 — update on Generated by Claude Code |
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk {
"issue": null,
"status": "done",
"branch": "claude/harden-webhook-redeliver-door",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27474",
"head": "b4a2146cb6c24b77a6a5244274195b2067e295b1",
"session": "session_017xRBcVy4VXmkQjn2MGeaWk — this run's harness-stamped id (subagent of the PM session; the commit trailers carry it)",
"premise_still_valid": true,
"summary": "REWORK of #27474 against contract review 6494462291 (FAIL at 957b96882b), pushed as f1c7919300, 1b07782bdb, b4a2146cb6 (no force-push, no merge of main, still draft). Must-fix: the entitlement gate now hands resolveRequestExecutionContext the door's own tenancy resolver (redeliverTenancyResolver: the kernel's getServiceAsync('tenancy') thunk where the kernel has one, so classifyAdmissionTenancyPosture tells never-registered (no posture) from registered-and-failing (AuthzStoreUnavailableError, which the gate's catch answers 503); the sync swallowing leg only on a factory-less KernelBase host, the split packages/mcp/src/plugin.ts records). The verdict carries the vetted context.tenantId and the replay is scoped to it, never to the raw claim. Beyond the review's literal text, a claim the composition did NOT keep is refused with the same NOT_ENTITLED 403: a dropped claim leaves tenantId undefined, which redeliverHttp treats as an UNSCOPED write, so threading it would have widened the door (ablation 2 measured exactly that: without the line the walled cases replay with no scope). Should-fixes: changeset declares Clause-② no (narrowing), the BREAKING banner and one adr-0087 not-required (no-migration-prescription) marker, summary line fix(plugin-webhooks)!:, level stays patch; once-at-boot warn at kernel:ready when the door is served (either face) and no security service can decide, naming @objectstack/plugin-security; the two service-messaging docblocks and the checklist clause verify field retired (webhook-lifecycle r13 citing #27474; steps[6] 'as an authenticated user' also fixed, same item); ADR-0124 anchor scripts/adr-anchors/packages__plugins__plugin-webhooks__src__redeliver-entitlement.ts.json (D1, D3 named in its invariant); docs section 8 states the organization vetting. Permission axis kept as implemented (update on sys_webhook) and marked pending maintainer in the proposed 维护者速读. The PR BODY IS NOT REWRITTEN: os-dev.md lets the dev write a PR body only at pr_create and never PATCH it, so the full proposed body (Clause-② no (narrowing), Metadata-protocol none, Skills-docs line, 维护者速读, notes, readings) is in field pr_body_rewrite and at /tmp/claude-0/-home-user-objectstack/bdda939c-7424-5594-af38-0e6fe5d7eeed/scratchpad/redeliver-rework/pr-body.md for the seat to write; the seat may also want the title to carry `!` (fix(plugin-webhooks)!: ...) to match the changeset.",
"tests": "All at b4a2146cb6, shared box, heavy runs under scripts/pm/os-verify-lock.sh. (1) pnpm --filter @objectstack/plugin-webhooks test: 'Test Files 24 passed (24) · Tests 252 passed (252)' (242 before), then typecheck (tsc + tsconfig.scripts + check:test-typecheck: OK), VERDICT command-exit 0. (2) webhook-redeliver-entitlement.test.ts alone: 'Tests 21 passed (21)' (11 before; new: isolated and group dropped-claim refusals with the byte-identical body of an unentitled member and nothing replayed, both faces; backed-claim control admitted with redeliverHttp called with tenantId org_a and the other org's delivery 404, both faces; boot line said exactly once with no security service; ObjectKernel registry: unregistered = no posture/admitted in claim, isolated = 403, tenancy factory throws = 503 + cause logged + security never asked). (3) @objectstack/http-conformance hono-webhooks-redeliver.conformance.test.ts 7/7; @objectstack/service-messaging typecheck exit 0 and pnpm test 'Test Files 62 passed (62) · Tests 739 passed (739)' (comment-only edits). (4) Ablations via scripts/ablation-replace.mjs (subject resolved from src, no dist leg), each restored with blob == HEAD and git diff HEAD empty: A1 tenancy: input.tenancy -> undefined (blob ea5e9bd6 to 59923a52): '6 failed | 15 passed (21)', the four walled refusals plus the ObjectKernel walled and failing cases red; A2 dropped-claim refusal line deleted (blob ea5e9bd6 to edbf3939): '5 failed | 16 passed (21)', the walled cases replayed unscoped; A3 boot-report call deleted (webhook-outbox-plugin.ts blob c13b3ae5 to 99057719): '1 failed | 20 passed (21)'. Direction observed: red, as predicted. Threading verdict.tenantId instead of the raw claim is not separately ablatable (they are equal on every admitted call by construction).",
"gates": "Local derived set: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (tree b4a2146c; it warned the tree is 29 commits behind origin/main, 6 derived-from files changed in that range; main not merged, per the after-PR-open merge rule, CI green), 104 commands run each with its exit captured before any pipe, then --ran: 'Run reconciliation — 104 derived, 104 run, 0 NOT-MEASURED, 0 UNRUN' · '✓ dispatch-gates --ran: 104 derived famil(ies) accounted for'. First-pass non-zeros and resolution: check:objectql-double-limit exit 1 (new limit-blind sys_member double; the red CI reported on 1b07782bdb 'Lint · CI, release & engine gates' / job 123411210842) fixed in b4a2146cb6, re-run exit 0; check-plugin-teardown-shape --self-test exit 3 (shallow clone, pinned control 621a4876 unreachable) re-run exit 0 after fetching that one commit at depth 1; check:skill-examples, check:dual-build-cjs-loads, check:i18n exit 3 (PREREQUISITE NOT MET) re-run exit 0 after full pnpm build (114/114). Also check:adr-anchors exit 0, check-nul-bytes OK. The reds the PM named on f1c7919300 ('Lint & Repo Gates' job 123411154846, 'TypeScript Type Check' job 123411158250) are roster jobs whose member lanes concluded 'cancelled' (superseded by the 1b07782bdb push), not findings. CI on final head b4a2146cb6 (check-runs read after the dogfood run): 50 check-runs, 37 success, 13 skipped, 0 failure; Lint & Repo Gates success, TypeScript Type Check success, Test Core success (8/8 shards), Build Core success, Governed Surface Queue Guard success, Test UI success, Lint · CI, release & engine gates success, Check Changeset success; Lint UI / Type Check UI / Build & E2E UI / Live E2E UI skipped (no ui/ paths). Note: CI's PR-body readers still read the old body ('Clause-②: no'); they re-run once the seat writes pr_body_rewrite.",
"dogfood_battery": "b4a2146cb6 · 'os-verify-lock: VERDICT command-exit 0 · held the lock 1362s (22m42s)' · Test Files 348 passed | 3 skipped (351) · Tests 2806 passed | 20 skipped (2826) · no failures (owed by the (narrowing) arm; run once after a full pnpm build)",
"mcp_calls": "0 — no MCP GitHub tool used; GitHub reads went through gh api (PR, review comment, check-runs) and scripts/pm/ci-failure.mjs",
"api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/27474/comments (this os-dev-report, through scripts/pm/post-stamped.mjs and the fleet-write relay). Not REST: three git pushes to claude/harden-webhook-redeliver-door (f1c7919300, 1b07782bdb, b4a2146cb6). PR body, title, labels, draft flag: not written.",
"deviations": [
"PR body not rewritten (os-dev.md: the dev writes a PR body once, at pr_create, never PATCH; the dispatch asked for the declaration lines in the PR body). The text is in pr_body_rewrite for the seat. Conflict noted, not silently resolved.",
"Checklist: the dispatch said bump the item and append a history row citing this PR; r12 of integration-system.webhook-lifecycle was already this PR's, so the bump is r12 -> r13 (ref #27474). The seat may collapse r12 and r13 into one row before landing if preferred.",
"The tenancy thunk does not use the plugin's swallowing tryGetService on an ObjectKernel (the review's wording): that would read a registered-and-failed tenancy service as absent. Reasoning in the module docblock and the proposed acceptance notes.",
"Added the dropped-claim 403 (not in the review's literal fix) because threading the vetted undefined tenantId would have been an unscoped replay; measured by ablation A2.",
"One security-class out-of-scope finding is withheld from the GitHub copy of this report under the disclosure ruling; the handback copy carries it in full."
],
"open_questions": [
{
"question": "Permission axis for redelivery (human floor, pending maintainer): keep `update` on sys_webhook as implemented, or a dedicated capability on the delivery object?",
"options": [
"A keep update on sys_webhook (as implemented; operators who may read deliveries but not edit webhooks lose the button; migration is an allowEdit grant)",
"B a dedicated capability on sys_http_delivery (decouples redelivery from editing the subscription; a spec change outside this PR)"
],
"recommendation": "A, as the contract review also recommends: a replay is a write-shaped act with an external side effect, the same power as re-activating the subscription; B is a follow-up only if the coupling proves unwanted"
}
],
"out_of_scope_findings": [
"class: a · reach: exception: security · withheld from GitHub under the 2026-10-29 disclosure ruling (security findings get no card); the full entry is in the handback report to the dispatching PM session",
"class: none (noted, not filed) · carrier: none · `packages/services/service-messaging/src/http-outbox-parked-record.integration.test.ts` docblock still says the redeliver door is one \"which any authenticated user can reach\"; it narrates the pre-#8069 state as history, so it was left as found and named in the proposed PR body's acceptance notes"
],
"pr_body_rewrite": "not inlined here: its details/summary blocks are tag-shaped text the comment sanitizer may eat. The full proposed body is in the handback copy of this report (field pr_body_rewrite) and in the dispatching session's scratchpad at /tmp/claude-0/-home-user-objectstack/bdda939c-7424-5594-af38-0e6fe5d7eeed/scratchpad/redeliver-rework/pr-body.md"
} |
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk Contract reviewServed-tier: Delta review of the rework against this seat's record 6494462291 (FAIL at 957b968): commits f1c7919, 1b07782, b4a2146. Inputs: the PR body as rewritten by the PM seat, the file list, the net diff against ① Derived judgmentsEach accept-set or public-surface change the delta implies, named against the cited code:
② Semver level
③ Boundary flags
④ Design judgmentNarrowing face, no Must-fix: none. The prior must-fix is resolved as stated and pinned on both faces; the new refusal arm is the right completion of it; nothing in the delta admits a caller Should-fix:
Held (no finding): the posture is read per request through the kernel's registry and recorded nowhere, so the startup-registry rule is not engaged; the boot report reads the registry at Implemented-by: VERDICT: PASS |
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk ACCEPT → head 维护者速读
席位意见:收。增量契约复核 PASS(6501041079),dogfood 全套 348 个文件、0 失败。 席位核对
Generated by Claude Code |
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk
Hardening dispatched directly by QA (domain:devx); no tracking issue.
Clause-②: no (narrowing)
Metadata-protocol: none
Skills-docs: none — no file under skills/** teaches the redeliver door (git grep -i redeliver -- skills: 0 hits at b4a2146); the page that does, content/docs/automation/webhooks.mdx section 8, is updated in this diff
Review owed before the queue: this narrows who may call a public door (
POST /api/v1/webhooks/redeliver). The contract-tier review of 957b968 (FAIL, one must-fix and four should-fixes) is answered at b4a2146; a delta review by that seat is owed on this head.维护者速读
POST /api/v1/webhooks/redeliver,两个入口面)在登录校验之后、读取请求体之前,由安全服务判定调用者是否有 Webhook 管理权限(sys_webhook的对象级编辑准入);判定所用的调用者上下文按部署的租户隔离姿态解析,与数据 API 一致:隔离姿态下,会话声称的组织若已无有效成员关系,该声明不被采纳,入口以同一个 403 拒绝;重投递只写入调用者被准入的那个组织。sys_webhook编辑权);隔离姿态下组织声明失效的会话改为 403(切换到自己所属的组织即可);未注册安全服务的部署改为 503,并在启动时打印一次提示。回滚即 revert 本 PR。待维护者定夺(人工底线,未在本 PR 内决定):重投递权限轴,按现实现为sys_webhook的update,备选为投递对象上的专用能力(需改 spec)。packages/plugins/plugin-webhooks/src/redeliver-entitlement.ts(租户解析器两条腿、被丢弃组织声明的拒绝、失败方向)、webhook-outbox-plugin.ts中serveRedeliver闸门段与重投递所用租户、webhook-redeliver-entitlement.test.ts新增的隔离姿态用例。pnpm --filter @objectstack/plugin-webhooks exec vitest run --maxWorkers=2 src/webhook-redeliver-entitlement.test.ts,预期 21 个用例全绿(含 isolated/group 下组织声明失效 403 且未重投、成员关系有效时放行且限定本组织、真实 ObjectKernel 上租户服务失败 503)。sys_webhook的update,或改为投递对象上的专用能力)。What changes
serveRedeliver(the one body both faces run: the self-hosted raw-app mount and thewebhooksslot'shandleRedeliver) asks, right after the auth gate and the401and before the request body is read, whether the signed-in caller may administer webhooks (redeliver-entitlement.ts):ExecutionContextcomes fromresolveRequestExecutionContext(the one platform composition), fed the session the door already read (session: { established }), so the gate judges exactly the identity the door acts as;ISecurityService.explain({ object: 'sys_webhook', operation: 'update' }, context).allowed(ADR-0124 D1: server-side);403 PERMISSION_DENIED, one fixed answer, so nothing in it depends on a delivery row; no security service, or a check that throws:503 SERVICE_UNAVAILABLE(ADR-0124 D3: an undecided case is never admitted; cause logged aterror).tenancyresolver (redeliverTenancyResolver), so the session's organization claim is vetted against the posture in force exactly as the data API's doors vet it (the per-request membership check of the 2026-09-05 ruling, option B). The resolver reads the kernel's async accessor (getServiceAsync('tenancy')) where the kernel has one, soclassifyAdmissionTenancyPosturesees the registry's own answer: never registered is no posture, registered and failing is the outage the gate'scatchanswers503. On a factory-lessKernelBasehost the sync accessor's only fault is "not registered", absorbed inside the thunk. The admission carries the vettedtenantId, and the replay is scoped to it, never to the raw session claim.403body. The replay is scoped by one organization; a dropped claim leaves none, and threading none would be an unscoped write, wider than any write the data API's gate gives that caller (with no active organization the tenant layer denies every row underisolatedand admits only the caller's own organizations undergroup, a set this door's single-tenant scope cannot express). The principal is not refused: the session stays signed in with no active organization, as option B prescribes; only this door's act, which needs an organization, is declined.kernel:ready, atwarn, that every caller will be answered503, naming the remedy (compose@objectstack/plugin-security).updateonsys_webhook, notreadonsys_http_delivery. Replaying a delivery is a write-shaped act (the row resets and a signed request goes out), the same power as editing or re-activating the subscription; a read-only principal holding a read wildcard must not gain it. The axis is pending the maintainer (see 维护者速读).401, the400body refusals, active-organization scoping (404outside it), the redelivery veto's409s, the200replay. The door still admits no API key.content/docs/automation/webhooks.mdxsection 8 states the gate and the organization vetting; checklistintegration-system.webhook-lifecycler12 (posture sentence) and r13 (this round: acceptance[4].verify no longer cites a no-capability docblock, steps[6] drives the redeliver as the seeded admin, the walled-posture refusal is named) andintegration-system.notification-org-and-redeliver-eligibilityr4; the two stale "any authenticated user" docblocks inservice-messaging(http-outbox.tsRedeliverOptions,sql-http-outbox.tsredeliver) now state the gate; an ADR-0124 anchor forredeliver-entitlement.ts; the dogfood authz matrix row; the engine-double ledger row; the changeset declares the narrowing (Clause-②: no (narrowing), the BREAKING banner, one ADR-0087 dispositionnot-required (no-migration-prescription)), levelpatch.Tests
At b4a2146 (local, on a shared box):
@objectstack/plugin-webhookspnpm test:Test Files 24 passed (24) · Tests 252 passed (252);typecheck(tsc, scripts tsconfig, test layer) exit 0,check:test-typecheck: OK.webhook-redeliver-entitlement.test.ts: 21 cases (11 before this round). New: onisolated, an administrator whose claimed organization no current membership backs is refused with the byte-identical body an unentitled member gets, nothing replayed (both faces); ongroup, a claim on an organization the caller left is refused for that organization's delivery and for the one it still belongs to (both faces); control, a backed claim is admitted, the replay is threaded with that organization and another organization's delivery answers404(both faces); the once-at-boot line for a kernel with no security service; on a realObjectKernelregistry, the resolver reads never-registered as no posture, a walled posture as the drop, and atenancyfactory that throws as503with the cause logged and the security service never asked. The security double now records the organization the caller's context was resolved in.@objectstack/service-messaging(comment-only edits):typecheckexit 0;pnpm testTest Files 62 passed (62) · Tests 739 passed (739).@objectstack/http-conformancehono-webhooks-redeliver.conformance.test.ts: 7/7.Ablations (one-time, not kept; tool: scripts/ablation-replace.mjs, subject resolved from source)
tenancy: input.tenancyreplaced bytenancy: undefined(anchor 1 to 0, blobea5e9bd6to59923a52):6 failed | 15 passed (21), the four walled-posture refusals and the twoObjectKernelwalled/failing cases red; restored, blob equal to HEAD,git diff HEADempty.ea5e9bd6toedbf3939):5 failed | 16 passed (21), the four walled refusals and theObjectKernelwalled case red (the replay went out unscoped); restored, blob equal to HEAD.kernel:readyhook (webhook-outbox-plugin.ts, blobc13b3ae5to99057719):1 failed | 20 passed (21), the boot-line case red; restored, blob equal to HEAD,git diff HEADempty.Acceptance notes
tenancyservice "through the sametryGetServicediscipline". The resolver deliberately does not use the plugin's swallowingtryGetServiceon a kernel withgetServiceAsync: it would read a registered-and-failed service as absent, the permissive-on-failure collapseclassifyAdmissionTenancyPostureexists to prevent. The sync, swallowing leg is used only on a factory-lessKernelBasehost, the same splitpackages/mcp/src/plugin.tsrecords.tenantIdrather than the raw claim has no behaviour difference on an admitted call (the gate refuses whenever they differ), so it is pinned structurally (the replay's organization is asserted in the control case) and not ablated separately.http-outbox-parked-record.integration.test.ts's docblock narrates the pre-[security] a dropped webhook subscription leaves no durable record — and the naive fix hands an operator aredeliverbutton that sends UNSIGNED #8069 state ("which any authenticated user can reach") as history, not as the current posture.tryGetService(['security'])treats a throwing lookup as absent, so a kernel that never registeredsecurityanswers503with a remedy, never a silent admit.sys_webhook(this plugin's configuration object), not of a host-renamedsubscriptionsObject.Verification
The live readings recorded on 957b968 (fresh showcase boot, member 403 / admin 409, 404, 400, 200 with the sink re-hit / anonymous 401) are unchanged in meaning by this round, which changes only the walled-posture organization vetting; the showcase boots on
single, where the claim stands as made. Not re-driven live this round.Local gates (derived set, b4a2146)
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE:Run reconciliation — 104 derived, 104 run, 0 NOT-MEASURED, 0 UNRUN·✓ dispatch-gates --ran: 104 derived famil(ies) accounted for, all 104 exit 0 atb4a2146cb6. First-pass reds and their resolution:check:objectql-double-limitexit 1 (the suite's newsys_memberdouble was limit-blind; CI red on1b07782bdb) fixed inb4a2146cb6, re-run exit 0;check-plugin-teardown-shape --self-testexit 3 (shallow clone, pinned positive control unreachable) re-run after fetching that one commit, exit 0;check:skill-examples,check:dual-build-cjs-loads,check:i18nexit 3 (PREREQUISITE NOT MET: unbuilt dist) re-run after a fullpnpm build(114/114), exit 0 each. CI onb4a2146cb6: 50 check-runs, 37 success, 13 skipped, 0 failure; the reds reported onf1c7919300werecancelledlanes superseded by the next push.Not run locally
pnpm lintand the repo-wide farm are CI's;test:reponot run (the diff edits norepo-project test). Full dogfood battery owed by the(narrowing)arm, run once atb4a2146cb6after a fullpnpm build:pnpm --filter @objectstack/dogfood testunder the verify lock,VERDICT command-exit 0,Test Files 348 passed | 3 skipped (351),Tests 2806 passed | 20 skipped (2826).Generated by Claude Code
Body refreshed by the PM seat 2026-10-29T15:22Z from the os-dev rework report.