Skip to content

docs(spec,plugin-sharing): the master_chain refusals can name the record's own master; canEdit no longer lists the attachment and comment parent gates - #22535

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22497-master-chain-docblock
Oct 9, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-22497-master-chain-docblock

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Fixes #22497

Clause-②: no

Four docblock sentences. No type change, no code change, no test change. @objectstack/spec and @objectstack/plugin-sharing patch: the built .d.ts of both carries the text (checked below, with a positive control).

What changed

  1. ControlledByParentWriteDenialLeg, the master_chain bullet (packages/spec/src/contracts/security-service.ts).
    • Before: "or a master ABOVE the record's own master has no relation to derive from, is not present, or has an empty master reference".
    • After: "or a master that is itself controlled_by_parent (the record's own master, or any master above it) has no relation to derive its own master from, is not present, or has an empty master reference".
    • The next sentence's frame changes from "Above the first hop" to "Past the record itself" (see Deviations).
  2. ISharingService.canEdit (packages/spec/src/contracts/sharing-service.ts). The write-depth paragraph said the sys_comment and sys_attachment parent gates "reach this service through this method"; it now says through {@link checkEdit}. The two-state-projection paragraph's caller list drops the sys_attachment parent gate.
  3. SharingService.canEdit (packages/plugins/plugin-sharing/src/sharing-service.ts). The same caller list drops the sys_attachment parent gate.
  4. ControlledByParentWriteUnresolvedReason, the record_not_found bullet (packages/spec/src/contracts/security-service.ts). Added by the domain:spec seat's order on the card, after the missing-row probe below.
    • Before: "A missing master row is not one of these outcomes: on the first hop the legs judge it as they judge any master row, and above the first hop it is the master_chain leg."
    • After: "A missing master row is not one of these outcomes: where the master governs its own rows the legs judge it as they judge any master row, and where it is itself controlled_by_parent the walk reads that row to derive the next master, so an absent row after the legs is the master_chain leg, on the first hop or above it."

The changeset's first bullet names this fourth sentence.

The allow-arm clause is not in this PR: it belongs to #22455's serving decision, per the triage comment on the card.

Measured before editing

The first hop. At this PR's base ee8751d41e, SecurityPlugin.assertControlledByParentWrite runs assertMasterRowEditable for the record's own master on the first loop iteration (security-plugin.ts:9473). It then sets masterObject = hopRel.master (:9477), which is that same master. When declaresControlledByParent(masterObject) holds (:9478) the walk resolves that master's relation (:9496-:9503), reads its row (:9507-:9515) and its master reference (:9516-:9523). Every one of those refusals names masterObject. The card's :9320-:9353 anchors have moved; the walk is now :9468-:9526.

Observed through the real engine middleware and the registered checkControlledByParentWrite member, on the fixture of controlled-by-parent-write-member.test.ts plus two rows. The probe was a throwaway copy of that test file; it was deleted and is not in this PR.

cbpm_line/line_above_dangling -> {"outcome":"deny","leg":"master_chain"} :: ... (master 'cbpm_quote' has no 'account' master reference to derive edit access from)
cbpm_line/line_missing_master -> {"outcome":"deny","leg":"master_chain"} :: ... (master 'cbpm_quote' record 'q_missing' is not present, so its own master access cannot be derived)
cbpm_orph_child/oc1           -> {"outcome":"deny","leg":"master_chain"} :: ... (master 'cbpm_orphan' declares controlled_by_parent with no relation to derive edit access from)

In all three the named master is the record's own master, not one above it. The suite's existing master_chain case is the first row of this probe. The second row is the missing-row case behind the fourth sentence: the record's own master is itself controlled_by_parent, its row is absent, and the answer is master_chain on the first hop.

The canEdit callers. #22513 is merged (ce3d0ad419) and is in this base. The attachment gate calls checkEdit (attachment-access-hooks.ts:402) and checkControlledByParentWrite (:428). The comment gate does the same (comment-access-hooks.ts:422, :448). Neither calls canEdit, and both type their sharing dependency as a pick of checkEdit alone. They still hand the service a context with the operation-private keys stripped, so the write-depth paragraph's behaviour (ownership matched at own) is unchanged. Both lists were stale. The "Write DEPTH is an input the CALLER supplies" section of the same file says the gates "ask this service" without naming canEdit, so it was correct and is untouched.

Verification

Head 9e21e91be7, base ee8751d41e. The commits up to 99f06a1073 carry the other three docblocks; the last commit adds the fourth sentence and one changeset clause.

At 9e21e91be7:

  • pnpm --filter @objectstack/spec build, then check:generated: all 15 generated artifacts up to date, --fix not needed. The built dist/contracts/index.d.ts carries the new record_not_found sentence. No generated artifact renders these docblocks: check:generated finds nothing stale.
  • dispatch-gates --commands with no paths re-derived the same 83 families over the same four paths (48 changed lines, +32/-16). 82 run, all exit 0, one NOT MEASURED. The changeset gates are among the 82. pnpm check:i18n and the lint doc-formula gate passed after their prerequisite builds.

Carried over from 99f06a1073, because the delta since is one comment sentence and one changeset clause on an unchanged path set:

  • @objectstack/spec contracts tests: 45 files, 441 tests passed. Not re-run at the new head.
  • @objectstack/plugin-sharing build and typecheck: green. Publish check with a positive control: its built dist/index.d.ts carries the edited SharingService.canEdit sentence and the unedited Tri-state UPDATE verdict docblock beside it; the old list text has 0 hits; files[] is dist, README.md, CHANGELOG.md.
  • The artifact-roster block: 48 of 51 run, 47 exit 0. The 3 PR-context guards, wired to this PR, exit 0.

NOT MEASURED: pnpm check:dual-build-cjs-loads (no whole-workspace build, per the dispatch). pnpm check:published-readme-exports exits 3, PREREQUISITE NOT MET for six unbuilt packages; the diff changes no README and no export. CI owns both. Not run, declared to CI: full suites, pnpm lint, the declared wide-population gates, the 5 path-scheduled CI jobs.

Deviations

  • One word-frame change in a second sentence. The card asks for one sentence. The sentence after it said "Above the first hop the check answers these as refusals". Once the first sentence says the record's own master can be named, that frame contradicts it, so it now reads "Past the record itself". It is a four-word change and reverts alone. The seat accepted it on the card.
  • The surface widened by one bullet by the seat's order on the card: the record_not_found bullet above. The changeset headline reads "four contract docblocks" for that reason.
  • origin/main moved 6 commits after the base. None touches the four paths of this PR (checked at faf6348508), so no merge commit was added.

Acceptance notes (noted, not edited)

  • A test title repeats the old wording. controlled-by-parent-write-member.test.ts:306 is titled "a master above the record's own master with no master reference"; its fixture is the first-hop case. The assertion (deny, master_chain) is right, so the title is the only thing out of step.
  • security/explain is also a canEdit caller (security-plugin.ts:5526, through canEditRecord) and neither list names it. That omission predates fix(service-storage,plugin-audit,plugin-security)!: the attachment and comment parent gates judge a controlled_by_parent parent through its master #22513.
  • Three more comments still list the sys_attachment parent gate as a canEdit consumer: permission-evaluator.ts:369-:370 and explain-engine.ts:1950-:1951, as does a dogfood fixture comment, packages/qa/dogfood/test/fixtures/attachments-fixture.ts:15. All three are comments outside the docblocks this card names, with no runtime reader.

Generated by Claude Code

claude added 2 commits October 9, 2026 19:51
…ord's own master; canEdit no longer lists the attachment and comment parent gates

The ControlledByParentWriteDenialLeg docblock said the master_chain arm's three
resolution refusals name a master above the record's own master. The walk
resolves the record's own master first, so when that master is itself
controlled_by_parent the refusals can name it too. The two canEdit docblocks
(ISharingService and SharingService) listed the sys_attachment and sys_comment
parent gates among canEdit's callers; those gates read checkEdit and the
master-detail write check now.

Docblock sentences only: no type change, no code change.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-sharing, @objectstack/spec, touching 2 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/contracts/security-service.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

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

  • content/docs/kernel/contracts/index.mdx (via ISharingService (symbol, a top-level interface))
  • content/docs/kernel/runtime-services/sharing-service.mdx (via ISharingService (symbol, a top-level interface))

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

  • content/docs/releases/v17/17-3.mdx (via SharingService (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
  • 1 changed file(s) yielded no anchor (packages/spec/src/contracts/security-service.ts) — pages documenting those are invisible to this run
  • 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 — 139 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 ce78ff7bcd850f440b2bacc25a35cedbcc847c56 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 915dc10c1774831192b2f4313a070b4c12bd3454 — the merge of head 4a6d71cfcda08d9bf78ecc959292bc516f43ee61 into base ce78ff7bcd850f440b2bacc25a35cedbcc847c56, 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 915dc10c1774831192b2f4313a070b4c12bd3454 && git checkout 915dc10c1774831192b2f4313a070b4c12bd3454
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ce78ff7bcd850f440b2bacc25a35cedbcc847c56 4a6d71cfcda08d9bf78ecc959292bc516f43ee61 && git checkout -B drift-repro ce78ff7bcd850f440b2bacc25a35cedbcc847c56 && git merge --no-ff 4a6d71cfcda08d9bf78ecc959292bc516f43ee61

node scripts/docs-audit/affected-docs.mjs --json ce78ff7bcd850f440b2bacc25a35cedbcc847c56

⚠️ 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 ce78ff7bcd850f440b2bacc25a35cedbcc847c56 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…the master_chain leg, on the first hop or above it

The record_not_found bullet of ControlledByParentWriteUnresolvedReason said the
legs judge a missing master row on the first hop and only above it is it the
master_chain leg. The walk reads a controlled_by_parent master's row after the
legs on every iteration, the first included, so an absent row there answers
master_chain. The changeset names the sentence.

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

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 9e21e91be753b7e2a3f899cc247cbd156bb1492e
Local-runs: none

Inputs: card #22497 (body and all seven comments), PR #22535 (body, its one comment, file list), the net diff of refs/pm/pr-22535 against its merge-base with origin/main (ee8751d41e; 4 files, +32/-16; origin/main is at faf6348508, six commits past the base), and the 46 check-runs on the head. The code each sentence describes was read at the PR head (git show refs/pm/pr-22535:…) and re-read at origin/main where that file moved.

① Derived judgments

Every hunk in the diff is inside a /** … */ block or the new changeset. No accept-set changes: no Zod schema, no type alias member, no export, no runtime line moves. The public-surface changes are TSDoc on four published docblocks, judged one by one against the code at this head:

  1. ControlledByParentWriteDenialLeg, master_chain bullet — RIGHT. SecurityPlugin.assertControlledByParentWrite (security-plugin.ts:9263) loops from the record's own master: iteration one runs assertMasterRowEditable(permissionSets, hopRel = rel, hopMasterId = masterId, …) (:9473), then sets masterObject = hopRel.master (:9477), which is that same master. When declaresControlledByParent(masterObject) holds (:9478), the no-relation (:9496–:9503), row-not-present (:9507–:9515) and empty-master-reference (:9516–:9523) refusals all throw masterEditDenied('master_chain', …) naming masterObject; the cycle (:9480) and depth-bound (:9488) refusals are master_chain too. So "a master that is itself controlled_by_parent (the record's own master, or any master above it)" is what the code decides. The adjacent frame "Past the record itself the check answers these as refusals, not as defects of the request" is also right: for the addressed record the same three conditions throw MasterDetailRelationMissingError (:9306), DetailRecordNotFoundError (:9321) and MasterReferenceMissingError (:9459), which controlledByParentWriteOutcomeOf maps to unresolvable; from the first master on they are the master_chain leg. The dev's four-word deviation ("Above the first hop" to "Past the record itself") is required by the first sentence, not optional.

  2. ControlledByParentWriteUnresolvedReason, record_not_found bullet — RIGHT. "This is the addressed record, not its master": DetailRecordNotFoundError is thrown only at :9321, for (object, targetId). Where the master governs its own rows the loop breaks at :9478 right after the legs, and nothing reads that master row for existence — only the row-level-security leg's findOne under the master write filter and the record-sharing leg see it, and they judge it as any row (they may pass; the sentence claims nothing stronger). Where the master is itself controlled_by_parent, readRowById(masterObject, hopMasterId) at :9507 runs after assertMasterRowEditable on every iteration, the first included, and an absent row is master_chain. "after the legs" correctly leaves the floor-constrained case (a leg refusing first) unclaimed; the dev declared it NOT MEASURED, and the sentence does not need it.

  3. ISharingService.canEdit, write-depth paragraph — RIGHT. At the head comment-access-hooks.ts:422 calls sharing.checkEdit(target.object, target.recordId, callerCtx) and attachment-access-hooks.ts:402 calls sharing.checkEdit(object, String(recordId), callerCtx); both type the dependency as a Pick of ISharingService on checkEdit alone (:137, :106) and neither calls canEdit. The retained clause "matches ownership at own" still holds through checkEdit: both callerContext helpers strip the operation-private keys (withoutOperationPrivateKeys), so no __writeScope reaches checkEdit and resolveOwnerScopeIds(context, undefined) matches at own.

  4. ISharingService.canEdit two-state caller list and SharingService.canEdit caller list — RIGHT as to the removal. canEdit callers at the head outside tests: sharing-plugin.ts:1263 (the sharing middleware), security-plugin.ts:5638 (resolveSharingCanEdit, the ADR-0055 master check's sharing leg) and security-plugin.ts:5526 (explain's canEditRecord binding). The two parent gates are no longer callers, so dropping them is right, and the two names kept are the two gating callers. Explain's binding is a reporter, not a gate that "ADDS this gate to whatever else guards the row"; its omission predates this PR and sits in the acceptance notes. Not a misstatement.

  5. Changeset text — RIGHT, one compression noted. "Each names the master whose own master the walk could not derive" and "Those gates read checkEdit and the master-detail write check" (checkControlledByParentWrite at comment :448, attachment :428) both hold; "keep their declared shapes" holds since no type or code line moves. The compression: "the legs judge a missing row only where the master governs its own rows" — the legs run on every hop before the row read, so a leg can refuse a missing controlled_by_parent master row first (the unmeasured floor case). The docblock's "after the legs" is the contract and states it precisely; the CHANGELOG sentence reads as the common case. Not a contract misstatement.

  6. Against current main. Of the files these sentences describe, only security-plugin.ts moved in the six commits past the base (d303b3e7af, PR fix(plugin-security): explain's update verdict on a controlled_by_parent record comes from the master-detail write check #22529: explain's update verdict now also asks checkControlledByParentWrite, and the pre-image floor vouch). The walk and assertMasterRowEditable are unchanged; the canEdit caller set at faf6348508 is the same three sites; both hooks are unchanged. Every sentence holds at main as well as at the base.

② Semver level

The diff publishes in exactly two packages, and each has its own entry in .changeset/22497-master-chain-docblock.md:

  • @objectstack/spec patch — right. files[] ships dist; src/contracts/index.ts re-exports security-service and sharing-service; tsup emits dts, so the three edited spec docblocks ship in dist/contracts/index.d.ts. TSDoc only; no export, authorable key or behaviour change, so patch is the floor and nothing reaches minor.
  • @objectstack/plugin-sharing patch — right. files[] ships dist; index.ts exports SharingService; its build is the root tsup config plus check-dts-emitted.mjs, so the edited SharingService.canEdit docblock ships in dist/index.d.ts. Same reasoning. (Both packages sit in the fixed group, so they version together regardless; the entry is still owed and present.)

No third package is touched. Clause-②: no appears in the changeset body and on PR body line 3 — right: no new key on any published payload, so no minor is owed and (widening)/(narrowing) do not apply. Not skip-changeset: both packages publish the text. Check Changeset (three runs) and Lint & Repo Gates (which carries the changeset gates: ADR-0087 registration, no-major / level axis, empty-changeset) are green on this head.

③ Boundary flags

open_questions: [] in both os-dev reports (6088993530, 6089641316). Nothing to answer.

Dev deviations, each answered:

  1. "Above the first hop" to "Past the record itself": required by the first sentence; right (①.1).
  2. ISharingService.canEdit edited in two sentences: both are the same caller-list claim; right (①.3, ①.4).
  3. Changeset headline "three" to "four": matches the diff, four docblocks across two files; right.
  4. No merge of origin/main into the branch: the check-runs ran on the merge of this head into faf6348508 (per the Docs Drift comment's tree line), the six commits falsify no sentence (①.6), and the queue rebuilds on landing. Acceptable.
  5. The surface widened by one bullet on seat order 6089034303: same file, same first-hop misstatement class, the ordered sentence landed verbatim; right (①.2).
  6. PR assignee unset (the dev's label-write --assign was refused by its classifier and not retried by another route): a process residue the owning seat holds per 6089680436; not a contract matter and not a reviewer write.
  7. The unquoted-heredoc incident (an unlocked spec build, check:i18n, two prerequisite-refused gates, a whole-repo lint terminated by recorded PID): the dev reports a clean tree afterwards, the three commits on the branch are exactly the diff read here, and none of those runs is cited as evidence. Recorded on the card; no effect on the contract.
  8. Contracts tests, plugin-sharing build/typecheck and the rosters carried over from 99f06a1073 rather than re-run at the head: Test Core (six shards), Build Core, TypeScript Type Check and Lint & Repo Gates ran on this head and are green, which is the verdict that counts.

out_of_scope_findings, each dispositioned:

  • The record_not_found bullet: resolved in this PR (①.2).
  • controlled-by-parent-write-member.test.ts:306 is titled for a master above the record's own master while its fixture is the first-hop case; the assertion is right. Neither a reproducible defect, a contract violation nor an authoring trap, so the acceptance note is the right carrier (Prime Directive chore: version packages #10). Not escalated.
  • Explain's canEditRecord unnamed in the two canEdit caller lists: pre-existing; a reporter, not a gate (①.4). Acceptance note; not escalated.
  • permission-evaluator.ts:369, explain-engine.ts:1950 and attachments-fixture.ts:15 comments still name the attachment gate as a canEdit consumer: code comments with no runtime reader, outside the docblocks the card names. Acceptance note; not escalated.

The red check on this head. 46 check-runs; every required context is green except Temporal Conformance (live PG + MySQL) (job 114021328084, run 37989816695), failure at step 2 Initialize containers: docker pull postgres:16 answered toomanyrequests: You have reached your unauthenticated pull rate limit three times with back-off, then Docker pull failed with exit code 1. Step 3 Checkout repository and every build and test step after it were skipped. The failure does not reach this PR's change: no source was checked out and no test body ran; it is a runner-side Docker Hub pull fault, which the seat's acceptance on the card (6089680436) names as p0 #22541. It is still one of the seven required contexts, so landing needs a green run of that job on this head or on a main-merged head — a landing condition for the owning seat, not a contract finding.

Governance and size. None of the four paths is a governed surface (Governed Surface Queue Guard green); this record is the compensating control the dispatch owes on the packages/spec/src/** limb. 48 changed lines, under the 3,000-line human-merge threshold; head repo is the base repo.

Implemented-by: claude/issue-22497-master-chain-docblock
Reviewed-by: session_01KNKBCRDJCu5tGy3TEbvtrF

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Regen-provenance: 6089801286 · 9e21e91be7 → 4a6d71cfcd · unexplainedPathsBetween(from, to, base: origin/main) → (empty)

domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T22:35Z.

The head moved after the contract review PASS 6089801286 by one merge of origin/main ce78ff7bcd (which includes PR #22545, the Temporal Conformance image mirror), and nothing else:

  • 4a6d71cfcd (parents 9e21e91be7, ce78ff7bcd);
  • git diff --name-only 9e21e91be7 4a6d71cfcd lists 64 paths main moved, none of them one of this PR's four paths;
  • scripts/pm/record-recognisers.mjs's unexplainedPathsBetween, run on the committed trees with base origin/main, returns no path;
  • git diff origin/main 4a6d71cfcd --stat is still the PR's 4 files, +32 / −16.

The record carries to 4a6d71cfcd. The merge exists so the required Temporal Conformance runs on the mirror; a re-run would have reused the old merge ref.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 9, 2026 23:02
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 9, 2026 23:02
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit b3a3634 Oct 9, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22497-master-chain-docblock branch October 9, 2026 23:28
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/s tooling

Projects

None yet

1 participant