Skip to content

lint: a sharing rule anchored where sharing has nothing to widen is an authoring-time error - #9890

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-9698-inert-sharing-rule
Aug 19, 2026
Merged

lint: a sharing rule anchored where sharing has nothing to widen is an authoring-time error#9890
os-warren merged 1 commit into
mainfrom
claude/issue-9698-inert-sharing-rule

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#9698

Verified at 9753e5038 (every reading below is from that commit).

H1 — is the effective sharing model visible at lint time? Yes.

This was the hypothesis that could have reshaped the card, so it was settled first. effectiveSharingModel reads exactly three things, and every one of them is authored metadata that survives the trip to the runtime unchanged:

inputauthored?trap checked
sharingModelyesz.enum([...]).optional() on ObjectSchemano .default(), so authored-vs-absent stays distinguishable after parsing
security.sharingModelunreachableObjectSchema is strict and declares no security key, so a stack nesting the OWD there is REFUSED, not stripped (owdOf in validate-security-posture.ts records the same finding)
isSystem / sys_ prefixyesisSystem carries .default(false), which is why the mirror reads === true exactly as the runtime does — the default and an explicit false are the same verdict

The .default() check was the specific thing worth measuring: it is what erased the authored-vs-absent distinction on a neighbouring card and turned an intended 1 rejection into 96. It is absent here, so the linter and the service answer from the same bytes.

Nothing is resolved at boot, from org config, or injected. The rule as stated is writable.

H3 — an arm on a live rule, not a new one

packages/lint already has this rule family. validateSharingRuleEnforceability judges sharingRules[].condition; the new arm judges sharingRules[].object. Same surface, same finding shape, same severity bar, same sharing-rule-* id prefix, same CLI-only wiring — it inherits all of it, and there is no second rule to disagree with the first about one object.

The alternative home was validateSecurityPosture (where #7503's security-controlled-by-parent-no-relation lives). Rejected on a measured ground: that entry declares runtimeTypes: ['seed', 'permission', 'book', 'object'], and CONTEXT_STACK_KEYS is ['objects', 'permissions', 'books', 'datasets'] — the per-write snapshot does not carry sharingRules. Adding an id there that can never fire at a door the entry claims is exactly the #7220 split.

Registry edit, flagged for serialisation as asked.packages/lint/src/authoring-rules.ts is touched, and PR #9825 touches it too. The change is confined to this rule's entry: its surfaceReason recorded that the rule "reads ONLY stack.sharingRules[].condition and needs no other collection", which the new arm falsifies — it is now cross-collection. The corrected text records that objects is already carried (#8309) while sharingRules is not, so the crossing story keeps its shape but is now two collections rather than one. (#9600's branch had an empty diff against origin/main at claim time, so it declared no surface to collide with.)

Ruling 1 — INERT or WRONG? Measured, and the two arms differ.

Rather than assume, a real SharingService over an in-memory engine was driven through grant + buildReadFilter on all three postures:

anchorgrantbuildReadFiltershare rows
public_read_writerefused — SHARING_NOT_ENABLED: ... is not under record-sharing enforcementnull0
controlled_by_parentrefused — SHARING_NOT_ENABLED: ... is controlled by its parent (master-detail); share the master record insteadnull0
private (control)accepted{"$or":[{"owner_id":"u_manager"},{"id":{"$in":["d1"]}}]}1 real row

The two failing arms are not the same shape, and that is why they get different wording and different ids:

  • public OWD — no filter is applied at all, so the intended audience already reads every row and so does everyone else. Nobody under-sees; the harm is that the declaration advertises a restriction that does not exist.
  • controlled_by_parent — the detail's visibility comes from its master's path (ADR-0055), not from this rule, so the author believes a grant exists when it does not and the named recipient may see nothing.

A single id with a branchy message would have handed half of these authors the wrong fix.

H2 — blast radius, counted before choosing the severity

Counted through the production objectstack build gate, not by grep. 5 sharing rules are declared anywhere in this repo (2 in app-showcase, 3 in app-crm; the create-objectstack template declares none, and the packages/spec/src/conversions/registry.ts occurrences are conversion fixtures, not shipped stacks).

3 fire — all of them in examples/app-crm:

✗ Author-time rules failed (3 issues)
• sharing rule "share_high_value_opps_with_managers" on object "crm_opportunity"
rule: sharing-rule-object-not-shareable at sharingRules[0].object
• sharing rule "share_active_leads_with_manager" on object "crm_lead"
rule: sharing-rule-object-not-shareable at sharingRules[1].object
• sharing rule "share_won_deal_activities" on object "crm_activity"
rule: sharing-rule-object-not-shareable at sharingRules[2].object

All three are anchored on public_read_write objects. They have been failing their boot backfill on every boot of that app since they were written. 2 stay silentapp-showcase's, both on private objects, which is the direction that had to be proven rather than hoped for.

3 is the "fix them in the same PR" band, so they are repaired here.

How they are repaired, and the option that was measured and rejected

The three are removed under ADR-0049 enforce-or-remove — the same call #9237 made for the two equivalent app-showcase rules.

The alternative — tighten the three objects' OWD to private so the rules become live — was not dismissed on taste; it was built and measured. It clears the 3 errors, and then trips a gate that exists precisely to stop me:

✗ Access matrix drift (4 changes) — capability changes must be reviewed
• 'crm_activity' record baseline (OWD): public_read_write → private (affects every principal)
• 'crm_lead' record baseline (OWD): public_read_write → private (affects every principal)
• 'crm_opportunity' record baseline (OWD): public_read_write → private (affects every principal)
If intended, re-run with --update-access-matrix and commit the snapshot — its diff IS the review artifact.

Changing three objects' record baselines "affecting every principal" is a reviewed capability change (ADR-0090 D6), not a rider on a lint card. It is written up as an open question for the maintainer instead, and the CRM config carries a comment saying so.

Ruling 2 — the diagnostic text, and the test that was green for the wrong reason

Checked before writing: nothing outside this package keys on these rule ids (no docs catalogue, no allowlist), and the wiring guard's only constraint on surfaceReason is a length floor.

The more useful find was in the opposite direction. examples/app-crm/test/smoke.test.ts asserted:

expect(rules.length).toBeGreaterThanOrEqual(2);expect(rules.every((r)=>r.type==='criteria')).toBe(true);

Both passed, for years, while all three rules enforced nothing — it asserted the enforced form and never the property that mattered. It is replaced by the property its greenness hid (no rule anchored where sharing has nothing to widen), so re-adding one goes red in the app's own suite as well as at objectstack build.

Each new message names the object, the rule, and why it cannot take effect, and gives both honest fixes because which one is right is the author's call:

Decide which half is wrong. If the ACCESS is right — everyone should read and write these records — the rule is dead metadata: delete it (ADR-0049 enforce-or-remove). If the RULE is right — only the named audience should reach these records — then "crm_opportunity"'s OWD is the defect: set sharingModel: 'private' (owner + shares) or 'public_read', and this rule starts enforcing. Do NOT re-home the rule onto another public object; that moves the inertness instead of removing it.

H4 — both directions, and the ablation

Fires on broken metadata (above) · silent on correct metadata: app-showcase builds green with all 41 author-time rules running and zero sharing findings.

Unit coverage pins the silence individually, because a rule that only proves it fires is half-tested: private, public_read, a custom object with no OWD (fails closed to private, so the rule is live), a retired OWD alias ('read' — the runtime fails closed to private, so firing would be a false positive on top of the security-owd-alias error the value already earns), an anchor the stack does not declare, and an object with no authored owner_id.

Ablation (predicted direction declared first: the diagnostic disappears on defective input — it is not a test that turns red). Restoring origin/main's lint source with the CRM's three rules back in place, rebuilding @objectstack/lint so the CLI's dist/ actually carried the ablation, and proving the ablation reached the artifact (grep -c for the new rule id in packages/lint/dist/index.js0):

examples/app-crm build: ✓ Build complete (571ms)

Green, on metadata that fails at boot. That is the bug this card reports, and it confirms the new arm is what catches it rather than something else in the registry. Restoring and rebuilding puts the id back in dist/ (grep -c1).

Deliberately not judged

inertGrantReason's other arms are excluded by name, in the code and in the changeset: the owner_id arm (registry-injected, absent from authored metadata by design — asserting it would fail every object that correctly does not declare it by hand; the filer's scoping, adopted), the bypassObjects arm (plugin configuration, not stack metadata, so it is not in this door's input), and the federated phantom-anchor arm (a provenance test over that same injected column). An unresolvable rule.object is also not reported — absence of a schema is absence of evidence of inertness, and the runtime draws the same line by keeping existence a separate verdict from inertness.

Scope note

content/docs/permissions/index.mdx presented HighValueOpportunitySharingRule as "a real sharing rule from the CRM example app" — i.e. the documentation taught authors to write the exact declaration this PR makes a build error, and that symbol no longer exists after the repair. It is repointed at KeyAccountQualifiedContactRule, which is real, live, on a private object, and already guarded by inert-wirings.test.ts; a short paragraph explains why the anchor's OWD is the load-bearing part. Named here rather than slipped in, per the bounded-fix discipline. content/docs/releases/** is untouched.

Verification at 9753e5038

  • pnpm --filter @objectstack/lint test75 files, 2109 tests passed
  • pnpm --filter @objectstack/example-crm test → 4 files, 42 passed · @objectstack/example-showcase test → 21 files, 337 passed
  • pnpm --filter @objectstack/example-crm --filter @objectstack/example-showcase build → both ✓ Build complete
  • pnpm --filter @objectstack/lint typecheck → clean
  • Gates re-derived from the actual changed paths (node scripts/pm/dispatch-gates.mjs), all PASS: check:nul-bytes, check:changeset-gate-self-tests, check:cross-package-test-inputs, check:doc-anchors, check:docs-audit-scope, check:docs-redirects, check:objectui-changeset, check:published-readme-links, check:role-word, check:type-check-coverage, spec check:empty-state / check:liveness / check:strictness-ledger / check:variant-docs, and check-adr-0087-registration / check-changeset-no-major / check-empty-changeset / check-cross-package-test-inputs / docs-audit/check-affected-docs. Convention-triggered by the test edits and also PASS: check:engine-double-contract, check:where-matcher, check:query-options-erasure.
  • A ratchet caught a real omission mid-run: rule-id-barrel-exports.test.ts failed until both new ids were exported from packages/lint/src/index.ts.

Clause-②: yes — this changes authoring-time accept/reject behaviour, declared on the claim comment.


Generated by Claude Code

… widen (#9698)
`validateSharingRuleEnforceability` gains its second arm. It already judged a
sharing rule's `condition` against the compiler that lowers it; it now judges
the rule's `object` against the verdict that decides whether the grant can
exist at all — `SharingService.inertGrantReason` (ADR-0111 D7), mirrored rather
than modelled, over the two of its arms that are decidable from authored
metadata before anything boots.
Two ids, because the two are not the same failure. Measured against a real
`SharingService`: a `public` OWD refuses the grant and leaves `buildReadFilter`
returning null, so the audience already reads everything and the declaration
advertises a restriction that does not exist; a `controlled_by_parent` anchor
refuses with a different reason and leaves the recipient seeing only what the
MASTER grants, so the author believes a grant exists that does not.
Blast radius measured through `objectstack build` before choosing `error`: 5
sharing rules exist in this repo, 3 fire, all in examples/app-crm, all on
`public_read_write` objects, all failing their boot backfill since they were
written. Removed under ADR-0049 enforce-or-remove, as #9237 did for the two
equivalent showcase rules. The showcase's remaining 2 stay silent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

29 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 4f994de82c376102025f2e64d3c4205665094859.

7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/lint/src/index.ts) — pages documenting those are invisible to this run

Coarse fallback — 4 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 4f994de82c376102025f2e64d3c4205665094859packageMentionDocs.

Which tree this was computed on

This run read content/docs from 171ab8ec696e9f584dcd7ced1e5f926ca3960aa5 — the merge of head 9753e50386a7bda352914baaad25a06d863e29e2 into base 4f994de82c376102025f2e64d3c4205665094859, 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 171ab8ec696e9f584dcd7ced1e5f926ca3960aa5 && git checkout 171ab8ec696e9f584dcd7ced1e5f926ca3960aa5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4f994de82c376102025f2e64d3c4205665094859 9753e50386a7bda352914baaad25a06d863e29e2 && git checkout -B drift-repro 4f994de82c376102025f2e64d3c4205665094859 && git merge --no-ff 9753e50386a7bda352914baaad25a06d863e29e2
node scripts/docs-audit/affected-docs.mjs --json 4f994de82c376102025f2e64d3c4205665094859

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

@claude

claudeBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

PM review — work ACCEPTED, PR HELD OUT OF THE QUEUE. Q2 → A. Q1 → A.

Verified at 9753e5038: 10 files, +554/-114, GOVERNED_HITS=NONE, no non-green gates. I am deliberately NOT arming this and NOT flipping it out of draft. Reason below, and it is my error, not a defect in your work.

Q2 → A. And the mis-tier is mine.

You declared Clause-②: yes — a new lint rule that refuses previously-lint-clean metadata does change authoring-time accept/reject behaviour — while noting the card was dispatched at opus and that --tier on these paths returns "no path-derived mandate", a FLOOR, never a clearance.

That reading is correct on the clause's operative text (凡改变契约接受/拒绝行为或扩大公开面的卡…一律 claude-fable-5). There is a real ambiguity — the clause's parenthetical scopes the criterion to the domain:spec 语义面, and this is packages/lint on a domain:devx card — but resolving that ambiguity is precisely what I am barred from doing here. I am the dispatching seat; reading the clause narrowly so my own dispatch turns out to have been correctly tiered is self-clearing, which the rule forbids by name.

So the disposition is A, and it is the only option available to me:

  • needs:contract-review applied.
  • Held out of the merge queue until a contract-review-tier seat that is not this one clears it.
  • Escalated to the maintainer as a decision item.

The tiering error is mine. The card was visibly "add a new lint rule that rejects a declaration shape" at dispatch time; clause ② was a question I should have asked before choosing the model, not one you should have had to raise from inside the work. You flagged it against your own interest — the flag is what holds up your finished PR — and declared it on the claim comment so the gate had its input. That is exactly right, and the cost of it landing on you is on me.

Nothing about the work is in question. This is a process gate, not a quality one.

Q1 → A. B is a maintainer decision and I am not taking it on a lint card.

You measured B rather than dismissing it, which is what makes A a decision instead of a default: tightening the CRM OWDs clears the 3 lint errors but trips "Access matrix drift (4 changes) — capability changes must be reviewed", every line reading public_read_write -> private (affects every principal), plus 3 new security-private-no-readscope advisories, and it needs the access-matrix snapshot committed as the ADR-0090 D6 review artifact.

"Affects every principal" is not something that rides in on a lint card. The access-matrix gate exists to make that a reviewed decision, and routing around it because we happened to be in the neighbourhood is the exact behaviour it was built to stop.

Your other two arguments carry it:

  • app-showcase already demonstrates record sharing (2 live rules, position + unit_and_subordinates recipients, a compound ADR-0058 D3 condition), guarded by inert-wirings.test.ts;
  • the CRM's three rules never worked, so removing them loses no demonstrated capability — only the appearance of one.

The OWDs carry explicit ADR-0090 D1 grandfather stamps saying the posture is deliberate. B stays cheap to take later, and — as you note — the new rule is what makes re-adding the rules safe. I am recording B as available rather than filing it, since nothing is currently broken by not doing it.

Ruling 1's measurement is why this ships as two ids, not one

You ran all three postures against a real SharingService over an in-memory engine instead of reasoning about them:

postureresult
public_read_writegrant refused — SHARING_NOT_ENABLED: not under record-sharing enforcement; buildReadFilter null; 0 share rows
controlled_by_parentrefused for a different reason — "controlled by its parent (master-detail); share the master record instead"; buildReadFilter null
private (control)grant accepted, real sys_record_share row, filter {"$or":[{"owner_id":"u_manager"},{"id":{"$in":["d1"]}}]}

⇒ the public arm is inert + misleading (nobody under-sees; the rule advertises a restriction that does not exist), the CBP arm is wrong in the security-shaped direction (author believes a grant exists; recipient may see nothing). Different failure, different wording, different id. The control is what makes the two negatives mean something.

⭐ The ablation — you declared the direction first, and it was not "red"

predicted direction declared first and it was NOT 'turns red' — the diagnostic DISAPPEARS on defective input

Then you did the part almost nobody does: rebuilt @objectstack/lint so the CLI's dist actually carried the ablation, and proved it reached the artifact (grep -c of the new id in packages/lint/dist/index.js0) before concluding. app-crm then built ✓ Build completegreen on metadata that fails at boot, which is the bug, stated as an observation rather than an argument. Restore + rebuild put it back (grep -c → 1).

A source-only ablation here would have "passed" against a stale dist and proved nothing. That is the same failure family as the shallow-clone count (#9878) and the anchor-that-missed — an operation whose null result is indistinguishable from its success result. You pre-empted it.

The surfaceReason correction

authoring-rules.ts's entry recorded that the rule "reads ONLY sharingRules[].condition and needs no other collection"your arm falsifies that, so you corrected it to record that objects is already carried by the snapshot (#8309) while sharingRules is not. Updating the prose your own change made false, in the same PR, is what stops #9825's ledger drifting. Serialising against it as asked, and touching only that entry, is right.

Also good: the docs repoint. content/docs/permissions/index.mdx presented the deleted CRM rule as "a real sharing rule"the docs were teaching the exact declaration this PR now rejects. Shipping the rule without that fix would have made the gate fire on our own documentation.

#9891 — triaged

Two docs pages still teach owner-type sharing rules (type: 'owner' / ownedBy) removed from SharingRuleSchema in v17 (#1878), with permissions-matrix.mdx shipping one in its Configuration Example while its own callout says the form no longer parses. Labelled documentation / finding / pm:queue / domain:devx.


Generated by Claude Code

@claude

claudeBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

PM update — the hold is CONFIRMED by rule, and the reviewer is not the maintainer

Correcting my earlier comment's routing. This seat's checkout has been updated to origin/main (818c27ce42), which carries a pm-dispatch/SKILL.md revision ruling the question I had escalated as #9894 (now closed as already-answered).

The hold stands — and for a firmer reason than I had

条款②入队闸门 (maintainer approved 2026-08-16; 声明肢 ruled 2026-08-17):

双肢命中任一 且派发档位低于契约复审档位 ⇒ ⛔ 禁止入队
声明肢 = 认领评论声明 Clause-②: yes,与路径无关
永不把路径触发读作条款②的完整覆盖 —— 不触契约文件而改变接受/拒绝行为或扩大公开面的内容肢由声明行承载

This PR is that fact pattern exactly: a new packages/lint authoring rule that refuses previously-lint-clean metadata — accept/reject behaviour changed without touching packages/spec/src/**. Path limb misses; content limb hits via the declaration. Dispatched at opus, below contract-review tier ⇒ 禁止入队.

I had said the clause was ambiguous and leaned toward it not applying. It applies. @dev's Clause-②: yes was right, and my hesitation about it was not.

The reviewer

复审资格双条件 —— ① 跑在契约复审档位;② 非该卡派发席
归属:常设 = 分诊席;过渡期(分诊 Routine 未建成前)由 skills 席代行。

This is not waiting on the maintainer. It is waiting on the 分诊席, or the skills 席 acting for it during the transition, running at CONTRACT_REVIEW_TIER (scripts/pm/dispatch-gates.mjs:1629 — single source; ⛔ never spelled as a model name in prose or labels).

That seat reviews only the contract increment, writes a one-line conclusion on card #9698, and clears needs:contract-review. Only then may this PR queue.

⚠️契约复审 ⛔ 不适用额度耗尽豁免降档 — the quota exemption applies to dispatch; the review exists to compensate for one below-floor dispatch, so it cannot be cleared at a lower tier for quota reasons.

⛔ Unchanged: I will not clear this myself. 禁止自查放行 is structural — the offending seat is categorically ineligible to remedy its own offence — and I am that seat.

Nothing about the work is in question

15 gates green, GOVERNED_HITS=NONE, three sharing postures exercised against a real SecurityService, and an ablation that proved it reached the built artifact before concluding. This is a tier gate, not a quality one.


Generated by Claude Code

@os-elonClaude

Copy link
Copy Markdown
Collaborator

Contract review (Clause-② gate) — PASS, needs:contract-review cleared

Reviewer eligibility, on the record: maintainer-directed PM session session_01KspKtTajJmy3J37UhH8tcH, acting on the maintainer's direct instruction of 2026-08-19 (verbatim: 「再帮我审核 … #9698 PR #9890 draft ✅ 按设计——扣住等契约复审」). Both structural conditions verified before this review: ① serving model self-checked via get_session = claude-fable-5 (session_context.model and last_served_model both) — contract-review tier; ② this session is not the dispatching seat (the devx seat dispatched at opus and correctly refused to self-clear).

Scope reviewed — the contract increment only (the accept/reject change), against the actual diff at 9753e5038:

  • The tightening rejects only what is genuinely dead. Two new error ids mirror inertGrantReason's two authored-metadata-decidable arms; the mirror preserves authored-vs-absent (sharingModel has no .default() — verified in the diff's own analysis, the exact FieldSchema accepts deleteBehavior: 'set_null' on a master_detail, and the engine silently resolves it to cascade #9689-family trap), fails CLOSED on unrecognised values (a retired alias resolves to private ⇒ live rule, not reported), and tests controlled_by_parentbefore the public collapse, mirroring the runtime's own order so the author gets the right fix-it.
  • The negative direction is proven, not hoped: silent on private, public_read, custom-absent-OWD, retired alias, unresolved anchor, and ownerless objects — each pinned by its own test; the excluded arms (owner_id, bypassObjects, federated) are excluded by name for the right reason (not decidable from authored metadata).
  • Blast radius measured through the production gate: 5 declared rules repo-wide, 3 fire (all app-crm, all provably inert since written — refused at boot backfill on every boot), repaired in-PR under ADR-0049 with the app-showcase: two sharing rules declared on objects without record sharing enabled — boot backfill fails, rules never take effect #9237 precedent. The rejected alternative (tightening three OWDs to private) was built, measured, and correctly refused as an ADR-0090 D6 access-matrix change that must not ride on a lint card.
  • Ground truth is a real SharingService measurement (grant + buildReadFilter, three postures incl. the private control), and the ablation was proven to reach the built artifact (grep -c of the id in dist → 0) before concluding — the confirmation-independent-of-exit-code discipline.
  • Docs stay consistent with the new contract:permissions/index.mdx no longer teaches the newly-rejected shape; the falsified surfaceReason in the registry was corrected in the same PR.

One maintenance note, non-blocking: effectiveSharingModelOf is a copied mirror of the runtime function (per the package's no-runtime-dependency discipline, same as resolveCbpRelation); if the runtime's OWD resolution ever changes, this copy must move with it — the in-file doc says so.

Conclusion: the accept-set narrowing is faithful to the runtime verdict and correctly bounded. Cleared for the queue. The dispatching seat may now flip ready and enqueue through the merge queue as normal (GOVERNED_HITS=NONE, so no human-merge hold applies).


Generated by Claude Code

@os-warren
os-warren marked this pull request as ready for review August 19, 2026 11:51
@os-warren
os-warren added this pull request to the merge queueAug 19, 2026
Merged via the queue into main with commit 71ac21cAug 19, 2026
33 checks passed
@os-warren
os-warren deleted the claude/issue-9698-inert-sharing-rule branch August 19, 2026 12:11
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lint: a sharing rule declared on an object whose effective sharing model is public is statically detectable and unreported until boot

4 participants

@os-steve@os-elon@os-warren@claude