Skip to content

fix(objectql): report a bound action named like one its target already lists, and registerAction replacing another owner's handler - #24526

Merged
objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-24472-bound-action-collision-report
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-24472-bound-action-collision-report

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #24472

Clause-②: no (a warning only: no accept set narrows, no door answer moves, and no published surface gains a key; owes the seat's review of record before the queue)

Dev session session_01PmE7dZP8v5iv3z1dgybAtT, dispatched by the domain:engine seat 1 (session_01JtSQQ3EWsbNPzyYMug1tXy) under claim 6264504693. It follows the maintainer decision 6262054499 ("18.x, report first"): the collision is reported, and nothing is refused.

What changes

  • The listing face (packages/objectql/src/registry.ts). The audit sits beside findUnboundActionTargets() on SchemaRegistry, keyed on FIND_BOUND_ACTION_COLLISIONS, a unique symbol declared in registry.ts and re-exported from neither index.ts nor core.ts, so the published face gains no nameable member (the shape of PR fix(objectql): a runAs:'user' hook sees its organization's members in sys_user, as the user's own request does #24518). The plugin calls it through that key. It returns each bound top-level action that its target object does not list, because the object already lists a different declaration under the same name. That declaration is either the object's own (rung 1 before rung 2, so attachBoundActions skips the name) or another package's bound action that was attached first. Each pair names the object, the action, the package whose declaration is served, and the package whose declaration is not listed. attachBoundActions itself is unchanged.
  • The sameness test. sameActionDeclaration compares two declarations structurally. At the top level it leaves out the provenance keys: every _-prefixed stamp (_packageId, _provenance, _packageVersion, the _lock envelope), the protection block those stamps translate, and objectName, which an object's own action leaves to its position. A pair that is one declaration carried twice is not a collision. Two cases are pinned: a same-stack bound action merged onto its object and kept at the top level (in compiled-artifact shape, so two copies), and one declaration shipped by two packages.
  • The report (packages/objectql/src/plugin.ts). At kernel:ready, right after the unbound-target refusal seals, the boot logs one warn per pair through describeBoundActionCollision. The boot always continues. Late artifacts are judged too. An artifact registered through the manifest service after kernel:ready (the boundActionTargetsSealed path: a marketplace install, a ledger rehydrate) is judged after it registers, and only for pairs that name one of its packages on either side. A pair the boot already reported is not reported again. The judgment comes after registration because a warning has nothing to refuse beforehand.
  • The handler face (packages/objectql/src/engine.ts, registerAction). When a registration lands on an OBJECT:ACTION key that another owner holds, it still replaces that owner's handler, so the last registration runs as before. It now logs a warn naming both owners and the consequence: the action door runs the new owner's handler whatever declaration the object lists, and withdrawing that owner leaves the action with no handler. The line drawn:
    • These stay silent: the same owner registering again (a re-bind, a reload), and the authored-action resync (removeActionsByPackage('metadata-service') runs before it registers).
    • A registration with no packageName is treated as its own owner.
    • The handler face sees handlers, not declarations, so it cannot tell "same declaration" apart from "different". When two packages carry one declaration, the handler face warns and the listing face does not. That is still a true statement: withdrawing the replacing package removes the handler the other package's declaration relies on (pinned).

Not built, by the ruling and the claim: no refusal, no new error code, no new key on the served object, and no change to the router's precedence.

Measurement M (booted composition, before and after)

Composition. os dev --fresh, using the CLI built from this tree. The host config composes two independent packages as two new AppPlugin(...) entries:

  • com.m.core owns crm_account, with an embedded script action whoami whose body returns { by: 'core' };
  • com.m.binder binds a top-level script action whoami (objectName: 'crm_account', body { by: 'binder' }) and extends the object with one field.

Registration order is the plugin order. Each row is a fresh boot: GET /api/v1/meta/object/crm_account, POST /api/v1/actions/crm_account/whoami, then a grep of the boot log.

case served declaration handler that ran boot log before boot log after
different, core first core's (Who am I (core)) binder's ({"by":"binder"}) nothing 1 listing warning (served com.m.core, shadowed com.m.binder) + 1 handler warning (app:com.m.binder replaces app:com.m.core)
different, binder first core's core's nothing 1 listing warning (same pair) + 1 handler warning (app:com.m.core replaces app:com.m.binder)
control, same declaration, core first core's core's body nothing 0 listing warnings, 1 handler warning
control, same declaration, binder first core's core's nothing 0 listing warnings, 1 handler warning
  • After the change, the served declaration and the running handler are identical to before in every row.
  • In the core-first row they disagree: core's declaration is served and the binder's handler runs. That is pre-existing and is now reported, by both faces.
  • Composed into one artifact instead: composeStacks already refuses the same pair at build time, identical declarations included ("cross-stack action key collision"). So the runtime collision exists only between separately installed packages, and that is the population measured here.

The named producer's shape (#24318), live. sys_organization with a late artifact. Marketplace install-local takes an inline manifest binding change_slug (type: url) to sys_organization.

  • Before: nothing is logged, change_slug is served from com.objectstack.plugin-auth (type: api), and the binder's declaration is listed nowhere.
  • After: one warning per arrival naming com.objectstack.plugin-auth and com.m.late3. It fired once when the ledger rehydrated at boot, through the sealed door, and once more on re-install. The served object is unchanged.

Volume on stock boots, after: examples/app-crm, examples/app-showcase and examples/app-todo give 0 listing warnings and 0 handler warnings each. Across the whole @objectstack/objectql suite (447 files), the handler warning fires 3 times, all from this PR's own pins.

Rider: stale attached copy after uninstall. Measured, not live, dropped

The card's steps, run on a booted composition with one package binding mrider_ping to sys_organization:

  1. GET /api/v1/meta/object/sys_organization lists mrider_ping@com.m.rider.
  2. Step 2 is refused. PUT /api/v1/meta/object/sys_organization with the served body answers NOT_OVERRIDABLE ("provided by a managed package and is sealed"), so no stored overlay can be written back from a served read through the REST door.
  3. Step 3 is refused for a booted binder. DELETE /api/v1/packages/com.m.rider and PATCH .../disable both answer WRITABLE_PACKAGE_REQUIRED.
  4. The one withdrawal door that exists, marketplace install-local DELETE, was measured with two late binders: com.m.late1 binds only, and com.m.late2 binds and extends sys_organization. After both are uninstalled, GET /api/v1/meta/object/sys_organization lists neither action.
    • The binding-only package never rewrote the boot-bridged MetadataService copy, which gets the action attached at read time.
    • The extending package's copy is restored by restoreExtendedObjectCopies from the registry's current definition.

The served answer is right on every reachable path, so nothing is built for the rider.

The optional boundCodeActions() index rider was not taken. The boot audit walks the bound actions once, each against a cached fold, and this PR does not otherwise touch that function.

Verification

All on head f679753aa (after merging origin/main f4755a68a) unless stated. Fix round 1 (bb02d9415) re-ran the pin file, the neighbour, the ablations, the build, the typecheck, core test:repo and all 72 derived gates; the objectql full suite stands from f679753aa.

  • Pins: packages/objectql/src/bound-action-collision-report.test.ts has 15 tests (plus a face pin: the key is exported from neither entry, and SchemaRegistry.prototype names no findBoundActionCollisions).
    • Registry: both orders; same declaration across two packages; the same-stack copy; a foreign-against-foreign pair; the narrowed set.
    • Report: a boot warning carrying exact meta and naming its subjects; the control boot; the late artifact; no re-report.
    • Handler face: replace and warn; withdrawal leaves no handler; a registration with no package; the silent same-owner and resync cases.
    • The neighbouring bound-action-foreign-object.test.ts stays green unmoved, 14 tests. Its pin "an action the object already declares under the same name keeps the object's declaration" still holds: the served answer did not move.
  • Pin sweep: grepped the tests that pin attachBoundActions' same-name skip and registerAction's replacement (bound-action-foreign-object, plugin-authored-actions, action-governance, engine-repo-execute-elevation, action-activation, and the runtime binder suites). None asserts that the replacement is silent, and none moves.
  • Ablations, mutated on disk through scripts/ablation-replace.mjs, each restored with git diff HEAD empty afterwards. The suite imports src by relative path, so no dist rebuild was needed.
    • Listing audit: the collision test is replaced by continue, and 7 of 15 tests go red.
    • Handler report: the replacement guard is replaced by false, and 2 of 15 go red.
    • Sameness: the top-level key set is replaced by a sentinel, and 3 of 15 go red (exactly the three "same declaration" controls). The first attempt at this one was refused by the tool as a no-op, because the replacement text contained the anchor. It was redone with a different anchor.
    • Face: index.ts re-exports the key, and 1 of 15 goes red (the face pin).
  • Package checks:
    • pnpm --filter @objectstack/objectql test exits 0: 447 files, 8406 tests.
    • pnpm --filter @objectstack/objectql typecheck exits 0, including check:test-typecheck.
    • pnpm --filter @objectstack/core test:repo exits 0: 6 files, 82 tests (measured on b848c4a36).
    • pnpm --filter @objectstack/spec check:generated exits 0 after the merge, because spec moved on main's side.
  • Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths, prints 72 commands. All 72 were run on f679753aa and again on bb02d9415, every one with exit 0, and every exit code was captured before any pipe. Reconciling with --ran gives "72 derived, 72 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)". check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET: 8 packages had no dist), so the 8 were built and the gate re-run, exit 0. The repo was deepened first (--shallow-since=2026-07-13) for check-engine-split-ratio --days 90 and check-plugin-teardown-shape.

Acceptance notes

  • Owner strings differ between the two faces. The handler face names the owner registerAction was given: app:ID from the runtime's artifact binder, or metadata-service. The listing face names the registry's package id, ID. Both are what each layer actually holds; no mapping is invented.
  • Two copies of the comparison. sameActionDeclaration is a local structural comparator. @objectstack/spec's deepEqualAuthored answers the same "same declaration?" question, but it is @internal and not exported, and exporting it would widen spec's surface. This PR now holds a second copy of that comparison. It has a provenance-key filter at the top level, which spec's does not need.
  • Who becomes the replacing owner. After a cross-package replacement, removeActionsByPackage(loser) removes nothing and removeActionsByPackage(winner) removes the key. The handler warning states this consequence. Changing it would mean changing which handler runs, which is out of scope by the ruling.
  • Measurement fixtures. The scratch compositions lived under examples/_m24472* during the measurement and were deleted. The repository's tree is unchanged apart from the five files listed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PmE7dZP8v5iv3z1dgybAtT


Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql, touching 13 documentable anchor(s).

10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via SchemaRegistry (symbol, a top-level class))
  • content/docs/data-modeling/objects.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/deployment/environment-variables.mdx (via SchemaRegistry (symbol, a top-level class))
  • content/docs/kernel/services-checklist.mdx (via ObjectQLPlugin (symbol, a top-level class), SchemaRegistry (symbol, a top-level class))
  • content/docs/kernel/services.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/permissions/authentication.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/plugins/adding-a-metadata-type.mdx (via SchemaRegistry (symbol, a top-level class))
  • content/docs/plugins/packages.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/protocol/kernel/index.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/ui/actions.mdx (via registerAction (symbol, a method of class ObjectQL))

⛔ 3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-0.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/releases/v17/17-1.mdx (via ObjectQLPlugin (symbol, a top-level class))
  • content/docs/releases/v17/17-4.mdx (via SchemaRegistry (symbol, a top-level class))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 3 anchor(s) matched too much of the corpus to be a work list: ObjectQL (symbol, 72 pages), objectName (symbol, 39 pages), objectName (literal, 39 pages)
  • 6 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 17 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 04669a467eb6443abab008586ff1813b9a366200 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 6ebf85042e05c375e76587d612c5db7a4b7ab157 — the merge of head bb02d94155ca3829199503f74b4fd4cd5410b79f into base 04669a467eb6443abab008586ff1813b9a366200, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 6ebf85042e05c375e76587d612c5db7a4b7ab157 && git checkout 6ebf85042e05c375e76587d612c5db7a4b7ab157
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 04669a467eb6443abab008586ff1813b9a366200 bb02d94155ca3829199503f74b4fd4cd5410b79f && git checkout -B drift-repro 04669a467eb6443abab008586ff1813b9a366200 && git merge --no-ff bb02d94155ca3829199503f74b4fd4cd5410b79f

node scripts/docs-audit/affected-docs.mjs --json 04669a467eb6443abab008586ff1813b9a366200

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 04669a467eb6443abab008586ff1813b9a366200 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: f679753aaf0a4971108df686511c8b1c7039f1c0
Local-runs: none

What this record read:

① Derived judgments

The listing audit: right, and report-only.

  • SchemaRegistry.findBoundActionCollisions walks boundCodeActions(). For each bound action whose target resolves, it reads the served object's actions, finds the same-named entry, and reports a pair only when the two declarations differ.
  • The sameness test, sameActionDeclaration, ignores the top-level _-prefixed stamps, protection and objectName; everything else is compared deeply. The pins show both directions:
    • one declaration carried twice, and a same-stack bound action merged onto its object, are not reported;
    • a differing label or target is reported.
  • The plugin warns once per pair at kernel:ready, beside describeUnboundActionTargets. It never throws, so the boot goes on, and the object keeps serving its own declaration (rung 1). This is the ruling's report-only shape: no accept set or door answer moves.
  • A late artifact is judged after it registers, narrowed to pairs naming one of its packages, and a pair already reported is not repeated (pinned).
  • Measured on the booted composition: in both registration orders the served declaration and the running handler are unchanged, and one warning appears. Stock CRM, showcase and todo boots log none.

The handler face: right.

  • registerAction warns when an OBJECT:ACTION key another owner holds is replaced, naming both. The replacement itself is unchanged, so the last registration still runs.
  • The same owner re-registering is silent, and so is the authored resync, which tears its set down first. A registration with no package is its own owner. All of these are pinned.
  • The message states a true, pinned consequence: withdrawing the replacing owner leaves the key with no handler.

The rider: measured and dropped. The card's step 2 answers NOT_OVERRIDABLE and step 3 WRITABLE_PACKAGE_REQUIRED, and the one withdrawal door that exists (install-local DELETE) leaves no stale copy. Right per the dispatch.

The pins: 14 cases in bound-action-collision-report.test.ts, and the neighbour bound-action-foreign-object.test.ts is unmoved. Ablations: the listing audit 7/14 red, the handler report 2/14, sameness 3/14 (exactly the three same-declaration controls). Each restore was checked.

② Semver level — does not hold

③ Boundary flags

  • Deviation 1, the handler face warns for one declaration carried by two packages (open question 1, A): accepted. The warning is true: the two packages' withdrawals are coupled through the one handler key, as pinned. Silencing it would need the declaration passed into registerAction, a wider public signature.
  • Deviation 2, the public @internal method: not accepted as committed; see ②.
  • Deviation 3, core test:repo measured before the last merge: Test Core 1/6–6/6 are green on this head. Accepted.
  • Deviations 4–6 (merge-commit trailers, the temporary local branch, the scratch compositions deleted before the gates): accepted.
  • Open questions:
  • out_of_scope_findings:
    • The orphaned handler after the winner's withdrawal sits inside the maintainer's refusal decision (6262054499), as the dev says. It is stated in the warning and pinned. Not filed.
    • The duplicate comparator (sameActionDeclaration beside spec's internal deepEqualAuthored) is an observation only. Not filed.
  • CI at this record: 40 check-runs on f679753aa, all completed, none failed.

Implemented-by: claude/issue-24472-bound-action-collision-report
Reviewed-by: session_01JtSQQ3EWsbNPzyYMug1tXy

VERDICT: FAIL


Generated by Claude Code

…symbol, so SchemaRegistry's published face gains no nameable member

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PmE7dZP8v5iv3z1dgybAtT
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: bb02d94155ca3829199503f74b4fd4cd5410b79f
Local-runs: none
Scope: delta review on the baseline record 6267837597 (head f679753aa, FAIL on ② only; the route was route A).

What this record read:

  • the fix-round report 6268501383, read as claims;
  • the one commit on top of the old head (bb02d9415, parent f679753aa), read with git diff on fetched refs: 3 files, +37/−16;
  • the net diff of this head against the merge base, compared per file with the old head's;
  • index.ts and core.ts at this head;
  • this head's check-runs.

① Derived judgments

What moved, and what did not.

  • The commit touches three files.
    • registry.ts: the key's declaration, the member renamed from findBoundActionCollisions(packageIds?) to [FIND_BOUND_ACTION_COLLISIONS](packageIds?), and three TSDoc links. The body is unchanged.
    • plugin.ts: the import gains the key, and the two call sites (the late-artifact path and kernel:ready) call through it, with arguments unchanged. One TSDoc line.
    • The pin file: the 14 earlier pins call through the key, plus one face pin.
  • engine.ts and the changeset are not in the commit, so their net patch is byte-identical to the baseline's.
  • Every judgment of record 6267837597 ① carries over unchanged: the listing audit, the sameness test, the handler face, the late-artifact narrowing, the rider and the messages.

The audit is gone from every nameable surface.

  • The key is Symbol('objectstack.objectql.findBoundActionCollisions'), not Symbol.for(...), declared const …: unique symbol. That is the form declaration emit needs for a computed member beside an unexported declare const.
  • index.ts and core.ts re-export from ./registry.js by name only, with no export *. Neither names the key, BoundActionCollision or describeBoundActionCollision.
  • Across packages/ at this head, the key is used only in registry.ts and plugin.ts (and the pin file).
  • The dev's .d.ts evidence (0 hits for the old name in either entry's declarations; the key declared only in the shared chunk, outside its export list) is consistent with that source reading.
  • A consumer of either entry cannot write the member's name in types or import its key. What is left is reflection on the prototype, the same reach every symbol-keyed member has, SEED_USER_GRANTS included.

The face pin is load-bearing.

  • It asserts that the key is absent from both index and core by name, and from index's values; that the prototype's own names exclude findBoundActionCollisions; and that its own symbols include the key.
  • Re-exporting the key from index.ts turns it red (the dev's A4, 1/15).
  • Re-adding the string name turns it red.
  • Dropping the symbol member turns it red, together with the 14 behavioural pins, which call through the key.
  • It checks both entries, the one gap PR fix(objectql): a runAs:'user' hook sees its organization's members in sys_user, as the user's own request does #24518's pin left.

② Semver level — holds

  • '@objectstack/objectql': patch with Clause-②: no now holds on the changeset (unchanged) and on the PR body's third line.
  • The published surface is the same set of nameable members and exported symbols as at the merge base. ObjectQLPlugin's reportBoundActionCollisions is private, so its declaration carries only a name.
  • Route A of 6267837597 ② is implemented as described there.

③ Boundary flags

  • PR body: it named SchemaRegistry.findBoundActionCollisions() and the old pin and ablation counts. The seat patches it to this head, using the dev's suggested wording from 6268501383.
  • The new deviation, the objectql full suite not re-run on bb02d9415: accepted. The round is a member re-key with no behaviour change. The pin file, the neighbour, the build, the typecheck, core test:repo and the 72 derived gates were re-run, and Test Core 1/6–6/6 run the full suite on this head in CI.
  • No merge of main: the dev's merge-tree against 04669a467e is clean. Accepted.
  • CI at this record: 38 check-runs on bb02d9415, 29 completed with none failed, 9 in progress. The ACCEPT waits on their conclusion.

Implemented-by: claude/issue-24472-bound-action-collision-report
Reviewed-by: session_01JtSQQ3EWsbNPzyYMug1tXy

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · domain:engine seat 1 · session_01JtSQQ3EWsbNPzyYMug1tXy · 2026-10-19T14:04Z · ACCEPT

Head: bb02d94155. The commits, in order: the listing audit and its boot report, the handler face, the pins, the changeset, a merge of main, and fix round 1 (the audit re-keyed on an unexported symbol). Card #24472 (p2, bug), claim 6264504693, dispatch 6264536317. Dev reports: 6267065299, and fix round 1 6268501383.

Item Reading
Shape Draft PR → main. The body says Fixes #24472. 5 files, +429/−3. Not governed: check-governed-merges on the final file list matched 0 of 5 paths.
Scope Listing: SchemaRegistry's audit, keyed on FIND_BOUND_ACTION_COLLISIONS, reports each bound action that its target does not list because the target already lists a different declaration under the same name. The plugin warns once per pair at kernel:ready, and for each late artifact. Handler: registerAction warns when another owner's OBJECT:ACTION key is replaced. Report only: nothing is refused, the router's precedence is unchanged, and there is no new error code. This is the shape of maintainer decision 6262054499.
Seat's own read The fix commit re-keys one member and its two call sites; nothing else moves. The key is a unique symbol that neither index.ts nor core.ts re-exports, and no other package names it. The changeset is '@objectstack/objectql': patch with Clause-②: no.
Review TIER_DEFAULT: record 6267837597 was FAIL on ② only (a public method on the exported SchemaRegistry). The delta 6268615812 is PASS on this head.
Declaration Clause-②: no on the claim, the PR body and the changeset. The PR body was patched to this head (the symbol key, and the 15-pin and ablation counts).
Cross-lane None. Every path is in packages/objectql, and the PR stays clear of the registry.ts extend refusal that #24341 holds.
Gates Dev, on this head: 72 derived, 72 run, 72 exit 0. Core test:repo 82/82. The objectql full suite was run on f679753aa (447 files, 8406 tests); Test Core 1/6–6/6 run it again on this head.
CI At this read on bb02d94155: ci-failure GREEN, all 40 check-runs completed, none failed. Mergeable, clean.

Disposition:

Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #24472 then closes the card.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants