Uh oh!
There was an error while loading. Please reload this page.
docs(services): five published service READMEs document the real plugin entry point, not a .configure() that never existed - #9602
Conversation
… not a `.configure()` that never existed (#9532) `service-analytics`, `service-automation`, `service-cache`, `service-i18n` and `service-job` each told a reader to import a `Service…` class from its own package and call a static `.configure({...})` on it. Neither has ever existed: no class in this repo exposes a static `configure`, and none of those five identifiers is exported by anything. All five READMEs are in their packages' `files` arrays with `private` unset, so they are the pages npm renders. Each README is rewritten against the package's BUILT type surface — the entry point is a kernel plugin constructed with `new` in every case — and each package's entry is deleted from `scripts/published-readme-exports.baseline.json` in the same commit (that baseline is reconciled in both directions, so a stale entry fails too): 16 entries -> 10. A name swap alone would not have gone green, which is the point of the gate landed in #9546: substituting the genuine class while keeping `.configure(...)` turns the import finding into a call-site finding rather than into silence. Also removed as fabricated: nine analytics REST endpoints of which none exists, a five-endpoint automation REST list matching no mounted route, fourteen `ICacheService` methods on a six-member contract, an i18n dialect with namespaces/plurals/formatters over a synchronous `t(key, locale, params?)`, and ten `IJobService` methods on a three-required-member contract. Two capability claims are corrected rather than deleted, because the source decides: `RedisCacheAdapter` throws from every method and `adapter: 'redis'` throws at init, and `JobServicePlugin`'s `adapter: 'interval'` stores cron registrations that never fire. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y26DJEHSBhhAQ6wwfsHNza
…hed surface (#9532) The value exports were listed but the 30 type exports were not, so the README's export list was a subset rather than the surface. A rerunnable set-equality check over the built `.d.ts` now reports 50/50 for this package (104/104 across all five), in BOTH directions — the gate proves every documented name resolves, it cannot prove nothing was omitted. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y26DJEHSBhhAQ6wwfsHNza
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 5 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 12 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-project-manager
commented
Aug 18, 2026
The two findings the body refers to are filed (both unassigned, both land in this repo, neither touched here):
#9611 explains why it was not absorbed here under the bounded in-place exemption: this diff's derived gate union carries no package test or typecheck job, and editing two Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32141617980 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
os-project-manager
commented
Aug 18, 2026
Triage of the queue failure — ⛔ do not re-queue. Branch 3: a semantic conflict with a sibling PR in the same group, not this PR and not flaky.PM dispatch seat, session 1 — is the failing test in a package this PR changed? No, structurally.Failing: This PR's entire diff: five 2 — flaky? No. The ratchet is firing exactly as designed.The test's own comment states its contract:
And 3 — ⭐ the actual cause: |
| fact | value |
|---|---|
FLOW_CONVERSION_CONFLICT registered in the ledger? | no |
still a pending-registration row in dispatcher-error-vocabulary.ts:365? | yes |
⇒ ratchet on main alone | consistent, green |
⇒ main is fine and this PR is fine. The red comes from a sibling in the same queue group: PR #9582 (#9567, spec lane) admits FLOW_CONVERSION_CONFLICT to the ledger — the spec seat's ledger records "half 1 (FLOW_CONVERSION_CONFLICT ledger admission, 292→293) ACCEPTED". Registration plus the still-present pending row is precisely the state the ratchet is built to reject.
What actually fixes it — ⛔ not mine to do
The remedy is the one the test names: the registering PR must delete the stale UNREGISTERED_CODE_SITES row in the same change. That is #9582's to carry, in the domain:spec lane (seat: os-steve, per #6017). I am flagging it there rather than touching another seat's PR.
⇒ Action for this PR: none. It waits for #9582 to land complete, or to leave the queue. ⛔ No push, no re-queue from this seat.
Generated by Claude Code
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9532
Piece 1 of #9532 — the five per-package README rewrites. Piece 2 (the gate) landed as PR #9546 (
1c6da6eaf, re-measured on currentmain) and is what makes this one checkable.What was wrong
service-analytics,service-automation,service-cache,service-i18nandservice-jobeach told a reader to import aService…-named class from its own package and call a static.configure({...})on it. Neither has ever existed. All five READMEs sit in their packages'filesarrays withprivateunset, so they are the pages npm renders.The real entry point in every case is a kernel plugin constructed with
new:service-analyticsServiceAnalytics.configure()new AnalyticsServicePlugin(options)service-automationServiceAutomation.configure()new AutomationServicePlugin(options)service-cacheServiceCache.configure()new CacheServicePlugin(options)service-i18nServiceI18n.configure()new I18nServicePlugin(options)service-jobServiceJob.configure()new JobServicePlugin(options)service-automationthe baseline's recorded "real export" isAutomationEngine. That is a real export but not the entry point —AutomationServicePluginis ("this is the only plugin needed for a fully-functional automation capability",src/index.ts). Taking the baseline'swhyas a prescription would have produced a second wrong page, which is the trap the cross-lane note on #9532 warned about. Every replacement here is proved forward against the built.d.ts.Evidence
1. The gate, green, with the baseline shrunk 16 → 10. The six entries these five files own are deleted in the same commit; the baseline is reconciled in both directions, so leaving one would have failed as stale.
2. Three ablations, each predicted before running, each restored afterwards (the working tree is byte-identical to the commit after the last restore —
git diff HEADempty):ServiceAnalyticsCacheServicePluginbut calls.configure(...)extractMemberCalls' regex requires a boundary character before the receiver and consumes it, so when the preceding match is discarded the next call on the same line loses its boundary:One space changes the verdict. The missed shape —
kernel.use(Plugin.configure(...))— is exactly what a careless rewrite of these five packages produces, since the correct spelling iskernel.use(new Plugin(...)). B2 shows the half is otherwise sound.3. Set-equality on the parts the gate cannot see. The gate proves every documented name resolves; it cannot prove nothing was omitted or that an option table matches the source. Two rerunnable checks, both measured against the built
.d.ts:AnalyticsServicePluginOptions8/8,AutomationServicePluginOptions8/8,CacheServicePluginOptions4/4,MemoryCacheAdapterOptions3/3,I18nServicePluginOptions5/5,FileI18nAdapterOptions3/3,JobServicePluginOptions4/4,IntervalJobAdapterOptions2/2,CronJobAdapterOptions6/6,DbJobAdapterOptions2/2), and every token in a README option table exists as a declared name in that package's ownsrc/— 0 fabrications in the reverse direction.runtime/src/domains/analytics.ts+POST /api/v1/analytics/dataset/queryfrom the REST ledger), automation 15/15 against the runtime route ledger's/automationdomain, i18n 3/3 againstI18N_ROUTE_LEDGER. cache and job: 0 routes in either ledger, matching their "No HTTP surface" sections.The nine fabricated analytics endpoints, the five fabricated automation endpoints and
POST /api/v1/i18n/translateare gone.Two capability claims corrected, not deleted
The card asked whether any of the five carried a compliance-style claim on top of the fabricated API, as
plugin-audit's did. Measured: none of the five mentions SOC 2, HIPAA, GDPR, PCI, ISO 27001, CCPA, FedRAMP, "compliance", "compliant" or "certif…". That shape is absent here. Two capability over-claims are, however, present, and the source decides both:service-cacheadvertised Redis as production support.RedisCacheAdapterthrowsRedisCacheAdapter not yet implementedfrom every method, andnew CacheServicePlugin({ adapter: 'redis' })throws duringinitrather than falling back to memory. The README now says so in a callout at the top and points at registering a customICacheServiceunder the slot.service-job'sadapter: 'interval'stores cron registrations that never fire. Now stated in the adapter table rather than left to be discovered.Also corrected against the source
ICacheServicehas six members; fourteen documented methods (mget/mset/del/delPattern/namespace/ttl/expire/persist/incr/incrby/decr/getOrSet/invalidateTag/resetStats) do not exist.set(key, value, { ttl })corrected to the real positionalset(key, value, ttl?)in seconds;CacheStats.keys/hitRatecorrected tokeyCountwith nohitRate.II18nService.tis synchronous and takes the locale positionally —t(key, locale, params?). The namespace/plural/context/returnObjects/formatter dialect and the{{lng}}/{{ns}}file layout were fabrications; the adapter reads one{locale}.jsonper locale with{{param}}interpolation only.IJobService.scheduleis positional —schedule(name, schedule, handler, options?)— and resolvesvoid. Retry defaults corrected to the enforced ones (maxRetries: 0,backoffMultiplier: 1,backoffMs: 1000,maxRetryDelayMs: 30000,jitter: false).IAutomationServiceisexecute(flowName, context?)+listFlows()plus optional members;AutomationResult's machine-readable field iscode, noterrorCode.useTranslationhook the i18n README imported from@objectstack/client-reactexists nowhere in this repo. That package shipsuseObjectStackLocale, which returns the active locale string — it is not a translator — so the client section is rewritten aroundObjectStackProviderplusclient.i18n.getLocales / getTranslations / getFieldLabels.Changeset
⭐ A
patchchangeset for all five packages, and the bump is the point rather than a formality: these READMEs reach a reader only through npm, and a docs-only fix with no version bump never gets published at all.Gates
Union derived by
node scripts/pm/dispatch-gates.mjsfrom the paths ingit diff --name-only $(git merge-base origin/main HEAD)and run ata5c5e3cff— the final commit — all exit 0:check:published-readme-exports·check:nul-bytes·check:changeset-gate-self-tests·check:objectui-changeset·check:test-source-alias·check:type-source-resolution·check-adr-0087-registration·check-changeset-no-major·check-empty-changeset·docs-audit/check-affected-docsThe union needs a built tree (the gate hard-errors on a missing type entry rather than skipping); the full workspace build ran first — 71 tasks, all successful.
⛔ Not touched:
scripts/check-published-readme-exports.mjs(gate gap filed instead), andplugin-audit's README — it is the gate's negative control and still passes.Generated by Claude Code