Skip to content

fix(plugin-sharing): require warn on the orphan sweep logger and pin every required warn - #12275

Merged
os-trump merged 1 commit into
mainfrom
claude/issue-10692-sharing-logger-required-warn
Aug 25, 2026
Merged

fix(plugin-sharing): require warn on the orphan sweep logger and pin every required warn#12275
os-trump merged 1 commit into
mainfrom
claude/issue-10692-sharing-logger-required-warn

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#10692

What this PR does — the ruled remainder of option A

The maintainer ruled option A on this card (2026-08-25): real signatures and a required warn on this package's logger sinks, with the check:optional-error-sink baseline rows paid down rather than made permanent. The producer half — the three publicly exported options types SharingServiceOptions, ShareLinkServiceOptions, SharingRuleServiceOptions — already landed on 2026-08-24 in PR #11856 under #10556 limb (c), together with the deletion of the three plugin-sharing baseline rows (the ledger is now 1 row, the recorded deliberate exception). This PR delivers what remained on this card:

  • record-orphan-cleanup.ts — the module-local MinimalLogger drops { info?: Function, warn?: Function } for the producers' real signatures ((msg: any, ...rest: any[]) => void) with a requiredwarn. Every report the sweep emits lands on warn (the "could not check", "stopped early" and "revoked N rows" lines), so a warn-less logger is one the sweep loses its only output into — A sink type declaring an optional error with no declared alternative is a contract that permits silence — require a fallback channel #9754's permit-silence shape, one module downstream of the producers Pay down the optional-error sink ledger — 13 paid, 2 remain and both are DESIGN CALLS (was: "15 sink types") #10556 tightened. In-repo call-site cost: zero — both callers forward the owning services' logger options, whose warn is already required.
  • logger-required-warn.pin.ts (new, src-level) — compile-time pins for all four sinks (the three public options types and the sweep's logger parameter): a { info, error }-only literal is refused, a bare { warn } stub stays legal (positive control), and a value of type Function no longer satisfies the members. A src-level .pin.ts because this package's tsconfig excludes tests from the tsc program a pin needs; the file deliberately declares no type literals carrying channel members, so the sink census never reads it.
  • logger-shapes.ts — the shape-map docblock's record-orphan-cleanup row no longer describes bare Function as blocked, and names the pin file.
  • Changesetminor with the published-contract break declared (BREAKING) and the one-line host fix named (add a warn callback, or omit the optional logger argument), per the launch-window convention and the refactor(plugin-auth): remove the inert AUTH_SCIM_PROVIDER_SCHEMA export (enforce-or-remove) #12008 precedent. ADR-0087 disposition: not-required (no-migration-prescription), accepted by the gate.

Dispatch-brief premise, re-verified against origin/main

The brief (2026-08-25 14:51Z) said the three public sinks were "currently baselined" and included the producer tightening in this card's surface. That was stale on arrival: PR #11856 (merged 2026-08-24 22:01Z) had already tightened all three producers and deleted their baseline rows. Verified byte-level on the base commit before any edit; nothing of #11856's work is redone here. The record-orphan-cleanup consumer, the pins, the sibling sweep and the changeset were the live remainder.

The load-bearing gate, run by hand on both sides

pnpm check:optional-error-sink, exit codes captured before any pipe, quoting the gate's own lines.

BEFORE (base cd2541780, exit 0):

SINK CENSUS [optional-error-sink-contract] (#9754): 41 sink type(s) declaring error in packages/** — 12 declare it REQUIRED (nothing to guarantee), 28 declare it optional beside a REQUIRED warn, 1 permit silence (1 optional-fallback, 0 no-fallback).
✓ optional-error sink contract: every sink declaring an optional error guarantees a warn channel (1 baselined, shrink-only).

AFTER (this PR's head 9abad39a1, exit 0): byte-identical population line and verdict line (diff of the two full outputs is empty), and the informational "99 pure sink(s) declare no error" tally is also unchanged — predicted in writing before editing: the sweep's sink declares no error member on either side of this change, so it never enters the population, and the pin file is invisible to the census by construction. The dispatch-measured trap (population 37 to 39, gate turning red) belonged to the pre-#11549/pre-#11856 tree; on today's tree the predicted movement was zero, and zero was observed.

Ablations — direction predicted in writing first, restored to HEAD

Fix committed first; each leg is a script with an EXIT INT TERM trap restore, an anchor asserted to occur exactly once before editing, and the mutation proven on disk by grepping the injected spelling (1) and the surviving old spelling (0). No build step exists in these legs to skip: the mutated file and the pins sit in one package compiled from source by a single tsc --noEmit, nothing resolves through dist.

  • Leg A — sweep's warn back to optional. Predicted: exactly 1 error, TS2578 unused-directive at the sweep refusal pin; bare-Function pin stays satisfied; exit 2. Observed: exactly that — logger-required-warn.pin.ts(72,3): error TS2578, 1 error, exit 2.
  • Leg B — producer SharingServiceOptionswarn back to optional. The original prediction (1 error) was amended in writing before running: with the sweep now requiring warn, loosening the producer must also break the forwarding seam. Amended prediction: exactly 2 errors — TS2578 at the SharingSink refusal pin, plus TS2345 at sharing-service.ts's sweep call. Observed: exactly that — logger-required-warn.pin.ts(66,3): error TS2578 and sharing-service.ts(1405,7): error TS2345, 2 errors, exit 2. The second error is the forwarding-seam diagnostic this type family exists to produce.

Both restores verified: git status --porcelain empty for the path and git diff HEAD --stat empty (disk == index == HEAD).

Sibling-host sweep (the ruling's own dispatch instruction)

  • objectui at ref 194fae184372ffe4c5719427d707a2900693fff2 (fresh clone of the default branch): zero imports of @objectstack/plugin-sharing (grep exit 1 over ts/tsx/json), zero warn-less logger literals (every single-line brace span naming both info and error also names warn; the only structural logger type found, packages/types/src/plugin-scope.ts:214, declares all three channels). Zero consumer cards to file.
  • cloud: ⚠️ NOT readable from this seat — the repository is not in this session's accessible repo list and the attach attempt was denied ("you don't have access to objectstack-ai/cloud"). This is a named gap, not a zero: the cloud half of the sweep still needs one grep by a seat with access. Recorded in the report's open questions rather than silently claimed.

Verification (all at head 9abad39a1, exit codes captured before any pipe)

  • pnpm --filter '@objectstack/plugin-sharing^...' build (dependency closure, via the shared verify lock): command-exit 0.
  • pnpm typecheck (plugin-sharing, script line echoed once): exit 0, 0 errors.
  • pnpm --filter @objectstack/plugin-sharing exec vitest run --maxWorkers=2: Test Files 27 passed (27), Tests 652 passed (652), exit 0.
  • check:optional-error-sink both sides as quoted above.
  • Derived gate list (node scripts/pm/dispatch-gates.mjs, no paths passed — 13 named + 2 convention): check:changeset-gate-self-tests, check:objectui-changeset, check:published-files, check:slot-lookup, check:test-source-alias, check:type-source-resolution, check-adr-0087-registration (judged this changeset declared-breaking, marker accepted), check-changeset-no-major, check-empty-changeset, check-plugin-teardown-shape, docs-audit/check-affected-docs, release-rehearsal-clone --self-test, check:i18n (after building the CLI it requires), check:i18n-stale-fill, plus check:nul-bytes — all exit 0.

Review status

Clause-② is yes per the dispatch: this PR carries needs:contract-review and stays a draft — the contract-review chain flips it, not this seat.


Generated by Claude Code

…n every required warn (#10692)
Part of #10692 — the ruled remainder (option A, maintainer 2026-08-25) after
PR #11856 landed the three publicly exported producers under #10556 limb (c).
- record-orphan-cleanup.ts's module-local MinimalLogger drops its bare
Function members for the producers' real signatures and makes warn
REQUIRED: every report the sweep emits lands on warn, so a logger without
a guaranteed warn is one the sweep loses its only output into (#9754's
permit-silence shape, one module downstream of the tightened producers).
Zero in-repo call-site cost: both callers forward the owning services'
logger options, whose warn is already required.
- logger-required-warn.pin.ts pins the contract at compile time for all four
sinks (three public options types + the sweep parameter): a
{ info, error }-only literal is refused, a bare { warn } stub stays legal,
and a value of type Function no longer satisfies the members. Pins live in
a src-level .pin.ts because this package's tsconfig excludes tests from
tsc; the file deliberately declares no type literals with channel members
so check:optional-error-sink's census never reads it.
- logger-shapes.ts's shape map is updated: the record-orphan-cleanup row no
longer describes bare Function as blocked, and names the pin file.
- Changeset: minor with the published-contract break declared (BREAKING) and
the one-line host fix named, per the launch-window convention.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQgPSniH1GFM9ZDeGyuGUa
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

5 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️1 changed file(s) yielded no anchor (packages/plugins/plugin-sharing/src/logger-shapes.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/plugins/plugin-sharing/src/logger-shapes.ts) — pages documenting those are invisible to this run
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 45 of 222 client-bound route-ledger rows — the other 177 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 177: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 107 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.

Coarse fallback — 8 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 f86839d4cd5543a0f8c7a3f4806b0d0b35a33524packageMentionDocs.

Which tree this was computed on

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

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

@os-trumpClaude

Copy link
Copy Markdown
CollaboratorAuthor

Contract-review verdict: PASS (#10692)

Reviewed by the contract-review chain at CONTRACT_REVIEW_TIER. Tier fuse, machine reading this sub-round: get_session.external_metadata.last_served_model = claude-fable-5.

Reviewed: the full diff (all 4 files), the changeset, and the ruling record on #10692.

Conformance to ruling A (maintainer 2026-08-25, 「同意」 — real signatures, required warn, baseline paid down):

One named gap, recorded rather than blocking: the ruling's out-of-repo sweep measured objectui (zero hits at the pinned ref) but cloud is unreachable — the dev seat's attach was denied, and this session's own attach attempt was denied identically just now. The cloud grep stays open for a seat with cloud access (or the maintainer). It does not block the PASS: a warn-less cloud caller, if one exists, gets a loud compile error naming the exact line on upgrade, and the changeset carries the one-line fix.

Landing completed by the chain in the same stroke per the maintainer's standing instruction (2026-08-25, verbatim: 「审核通过你应该直接负责合并吧,还要等原始的项目经理吗」): clearing needs:contract-review on this PR and #10692, flipping ready, arming the queue — CI green lands it.


Generated by Claude Code

@os-trump
os-trump marked this pull request as ready for review August 25, 2026 16:41
@os-trump
os-trump added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit 3194c91Aug 25, 2026
40 checks passed
@os-trump
os-trump deleted the claude/issue-10692-sharing-logger-required-warn branch August 25, 2026 17:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plugin-sharing declares six separate MinimalLogger types, now divergent after #10556

2 participants

@os-trump@claude