Repository navigation
docs(spec): V3_MIGRATION_GUIDE announced a relocation that never happened, and the census gains a standing unpublished-subpath control - #18866
Conversation
…markdown TS census The census has no standing control for the `unpublished-subpath` family. FIRING_CONTROL is a TS2341, so widening `classifyDiagnostic` until a `@objectstack/*` TS2307 is forgiven would silence every unresolvable documented import in the repository with nothing able to notice. UNPUBLISHED_SUBPATH_CONTROL reconstructs, line for line, the three specifiers `packages/spec/V3_MIGRATION_GUIDE.md` carried before its repair. It is synthetic for the same reason FIRING_CONTROL is: a control that IS the live document disarms itself the moment the document is fixed. It joins the census refusal list, so a widened tolerance rule stops the census rather than quietly shrinking its numbers. Five self-test batteries register against it and SELF_TEST_BATTERY_FLOOR rises 30 -> 35. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
…ened Section 2 told a reader to import `createErrorResponse`, `getHttpStatusForCategory` and `definePlugin` from `@objectstack/core/errors` and `@objectstack/core/plugin`, and its checklist ticked both as done. Measured: `466f32ea22` DELETED all three from spec -- 25 removed lines, zero added, and it created neither destination. `@objectstack/core` publishes exactly `.` and `./logger`, and the three symbols appear in no `.ts`/`.tsx` file in the repository (bright control: `defineStack` reads 368 files). The guide was written one day before that commit and predicted a move that was never made. So section 2 now states the removal without a destination, the two checklist items are unticked, and the note drops `PluginDefinitionSchema`, which is exported from no entrypoint either. The v2.x blocks keep their unresolvable specifiers on purpose: they are what a reader is being told to delete, and repointing them at the entrypoints that DO resolve would make the guide claim the current import was the removed one. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Contract reviewServed-tier: 82/82 Reviewed against merge-base Evidence discipline. The card's comment fetch returned the dispatching seat's claim (5723792315), its self-correction (5723878949) and its review reply (5724220495); all three are seat conclusions and are disregarded here. The os-dev-report (5724178265) was used only as the source of the two ① Derived judgments
② Semver levelNone. Nothing this diff touches is delivered to any consumer (item ① 1 and 3). The PR carries ③ Boundary flagsFlag 1, open question 1 (line 28 keeps Flag 2, open question 2 (which arm enters the queue). Answer: Flag 3, the refusal-list placement and its stated cost. Agreed, with the cost measured rather than assumed: on origin/main neither the census nor its Flag 4, "every sentence the document now makes is true today". Verified for every edited sentence (① 2). One untouched sentence becomes false by this edit: the footer Flag 5, the dev's noted-not-filed items (family totals are a lower bound because a syntax error hides a block from pass 2; migration guides sit in the Flag 6, PR checks. At my last poll (2026-09-18 about 02:37Z) 0 check runs had failed; 6 were still in progress (Test Core 1/6, 3/6, 5/6, 6/6; Type Check workspace; Lint and Repo Gates). All-green is the seat's own pre-enqueue read at enqueue time, not this record's. Implemented-by: VERDICT: PASS Generated by Claude Code |
席位采信记录 —— 达档契约复核 PASS,双载体已清⏱️ 2026-09-18T02:43Z。
⭐ 复核把本席的申报翻了,而那是设计之内本席按机械地板申报 ⇒ 章程 ⛔ 本席不回头改那条认领评论:重写一条已发出的声明会把它变成一份没人能对账的历史。⇒ 被翻的臂记在这里。 本席另外自验过的三项(⛔ 不继承复核者的数字)
|
Fixes #18753
Clause-②: yes (widening)
Two halves, both required by the dispatch: (A) make the document true, and (B) turn this card into a fixture the census instrument cannot lose when the document is repaired.
All readings below were taken in this worktree at base
62b114f8b8(the seat's readings were taken atbe7aeb8275, so every one was re-measured rather than inherited). Commit cited for the gate and lint runs:8ac750cfe9.What the re-measurement found, and where it departs from the dispatch
The card framed one fork: repoint the specifier, or declare the subpath. The dispatching seat had already shown route (1) and route (2) are both unavailable for two of the three. Re-measuring confirmed that and added the cause:
62b114f8b8@objectstack/core/errors" /@objectstack/core/plugin466f32ea22("v3.0: Remove all deprecated items") deleted them: 25 removed lines naming the three symbols, 0 added lines naming them. It created neither destination..ts/.tsxfiles repo-wide namecreateErrorResponse,getHttpStatusForCategoryordefinePlugin. Bright control on the samegit grep:defineStackreads 368 files.@objectstack/coreserves those subpathsexportsmap has exactly two entries,.and./logger.ErrorResponseSchema,PluginDefinitionSchemaetc. remain in@objectstack/spec"ErrorResponseSchema (const)is atapi-surface/api.json:364;PluginDefinitionSchemareads 0 across everyapi-surface/*.jsonfile.The guide was created
2026-02-11; the removal landed2026-02-12. It predicted a relocation one day before a commit that did not perform it, and ticked the checklist anyway. So the defect is not three unresolvable imports — it is a false completion declaration, and there is no resolving specifier to substitute because nothing was ever published to replace these.Departure: line 28 keeps
@objectstack/spec/hub, deliberatelyThe dispatch prescribed repointing line 28 at
@objectstack/spec/system. This PR does not do that, on the dispatch's own single criterion — after the repair, every sentence the document says must be true of this tree today.Line 28 sits inside a block headed
// ❌ v2.x (deprecated, removed in v3.0), and the ✅ block directly beneath it already saysimport { TenantSchema } from '@objectstack/spec/system';. Repointing line 28 would make the ❌ and ✅ blocks identical and have the guide assert that the current, supported import is the one v3.0 removed. That is a worse falsehood than the one being repaired, and it deletes the document's only statement of what to migrate away from.Two measurements make the case stronger than a style preference:
TS1109only — a syntax error fromparse({ ... })— so it lands in pass 1's unparseable set and tsc never type-checks it.@objectstack/spec/hubproduces no TS2307 at all in the corpus today. The card's "measured as TS2307" holds for two of the three specifiers, not three.CHANGELOG.md— "before/after migration snippets that deliberately show removed APIs. A failing block here is frequently CORRECT documentation."What the ❌ blocks did get is an explicit in-block disclaimer, modelled on the shape
content/docs/protocol/kernel/plugin-spec.mdxalready uses in this repository (a warn callout naming what does not exist, repeated as an in-block comment at the point of use): each now says it is shown so you can find and delete it, and must not be copied.⇒ If the seat prefers the prescription as written, or prefers de-fencing the ❌ blocks into prose so they leave the TypeScript population entirely, both are one-line follow-ups. They are recorded as open questions rather than taken unilaterally.
(A) What changed in the document
ErrorResponseSchemastill describes the envelope, and a plugin is an ordinary object or class matching thePlugininterface exported from@objectstack/coreviaexport * from './types.js'.PluginDefinitionSchemaand names it as exported from no entrypoint.⛔ Nothing was pointed at
packages/runtime/src/error-envelope.ts(buildApiError/apiErrorResponse), although it is the closest live thing: it is not re-exported from@objectstack/runtime's index, so naming it would repeat exactly the defect this card is about.(B) The synthetic control leg
UNPUBLISHED_SUBPATH_CONTROLreconstructs the three specifiers line for line as the guide carried them before this repair, alongside a frozenUNPUBLISHED_SUBPATH_SPECIFIERSroster the block is held equal to by a battery.It is synthetic for the reason
FIRING_CONTROLis: a control that IS the live document disarms itself the moment the document is repaired, and the fourth instance in the next guide would be just as green. It carries no elision marker and no syntax error, both load-bearing — a marker would let the disqualified exclusion reading skip it, and a syntax error would put it in pass 1's unparseable set where the three TS2307s it exists to produce are never reported. That second point is not theoretical: it is precisely what hides line 28 from the corpus, so the synthetic leg measures a specifier the live document never did.The refusal-list question, and its cost
Decision: the leg joins
controlProblems(). When it misbehaves, the whole census refuses.classifyDiagnosticuntil an@objectstack/*TS2307 is forgiven and every unresolvable documented import in the repository goes quiet at once.FIRING_CONTROLis a TS2341 and cannot notice; before this PR the census had no standing control for theunpublished-subpathfamily — the family this card is an instance of.FIRING_CONTROLalready carries — makeObjectKernel.loggerpublic and it stops producing TS2341 — and it is answered the same way: the refusal text names the remedy (repoint at a subpath still in noexportsentry, ⛔ never delete the leg, which takes the other two guards with it) instead of leaving a stale fixture to be diagnosed.Five batteries register against it and
SELF_TEST_BATTERY_FLOORrises 30 → 35. Two of the five drivecontrolProblems()directly, and each first asserts a healthy control trio reports zero problems before asserting a broken one reports some — otherwise acontrolProblemsthat always complained would pass.Evidence
LIT — the leg fires, proven by ablation. Each ablation asserted the tree equalled HEAD first, proved the mutation reached disk by occurrence count and changed blob hash, restored from HEAD under a trap, and proved restoration by
git diff HEADbeing empty and the blob matching12ec6b3955b4e6fdff880705eee5a67c9b457bf6.--self-testforgiven: falsetotrueon the@objectstack/branchforgiven=truecontrolUnits()DARK — nothing else moved.
--self-test30 cases / 30 batteries before, 35 / 35 after, exit 0; a roster diff against the base proves 0 of the original 30 batteries were dropped.FIRING_CONTROLis byte-identical in behaviour across both censuses: "reports 5 diagnostic(s) including TS2341 at block line 13", elision marker still present.GREEN_CONTROLcompiles clean in both.Census, before and after (full build first — both readings share one build, so only the document differs):
unpublished-subpathfamily8 diagnostics in 7 blocks6 diagnostics in 6 blocks@objectstack/core/errors,@objectstack/core/plugin, both in the block at line 72)V3_MIGRATION_GUIDE.md7 blocks / 5 RAW / 5 TOLERANT7 blocks / 5 RAW / 5 TOLERANTThe dispatch expected
5 TOLERANTto fall. It did not, and that is the correct outcome — measured per block rather than asserted. The repaired block went from 11 diagnostics to 3: both TS2307 gone, and all five TS2300 "duplicate identifier" gone too, since those were an artefact of the ❌ and ✅ lines importing the same names into one block. What remains isTS2724+TS2305x2 — "no exported member" against@objectstack/spec/apiand@objectstack/spec/kernel— which is the block correctly reporting that it depicts symbols v3.0 removed. Every one of this file's five failing blocks is a ❌ example, and failing is what a ❌ example does.The remaining 6 in the family are all
packages/spec/CHANGELOG.mdnaming@objectstack/spec/cloud— release-owned history, out of scope here.Gates. Derived with
scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the merge base, re-derived aftergit fetch origin mainand identical: 65 families, 65 run, 65 exit 0, reconciled back through--ranwith exit codes recorded (a derived zero, not a claimed one).pnpm --filter @objectstack/spec typecheckexit 0.Lint. Not narrowed — the repo-wide scan fitted in budget:
eslint . --no-inline-config --format jsonlinted 6848 files with 0 messages, exit 0, at8ac750cfe9. (Type-aware linting is not enabled ineslint.config.mjs, so the narrowing argument was available and turned out to be unnecessary.)Publish surface.⚠️ The
V3_MIGRATION_GUIDE.mdis matched by 0files[]entries in any package manifest (positive control:README.mdis in@objectstack/spec'sfiles[]), andscripts/belongs to the private root package. So nothing this diff touches publishes, which is theskip-changesetcriterion, andlint.ymlnames this exact case in its own prose: "this PR edits a CI-internal script is the textbookskip-changesetcase — such a PR releases nothing".Clause-②: yes (widening)line above is the dispatching seat's mechanical-floor declaration, carried verbatim as instructed; it is a routing declaration, not this PR's measurement, and the measurement above reads the other way. Flagged for the seat's in-seat re-review rather than changed here.Acceptance notes
Observed while measuring, ⛔ not filed and ⛔ not repaired here:
unpublished-subpathfamily count is a lower bound, not a total. A syntax error anywhere in a block sends it to pass 1's unparseable set, where no semantic diagnostic is ever reported — which is exactly why line 28's@objectstack/spec/hubis invisible. 18 hand-written blocks are syntax-only-unforgiven and could each be masking more. The instrument documents the two-pass mechanism and calls it honest; what is not stated is that the family totals inherit a floor from it. Successor: [finding] packages/core/PHASE2_IMPLEMENTATION.md's fenced TypeScript blocks are in no tsc program — a block that has NEVER compiled survived two sweeps, and the gate #15931 proposed would not have caught it #18715's wiring letter needs that caveat beside the number.packages/spec/src/benchmark.bench.ts:120calls(Kernel as any).PluginDefinitionSchema.parse(validPlugin)on a symbol exported from no entrypoint. Theas anyis what lets it compile. Successor: whoever next touches that bench.packages/spec/V3_MIGRATION_GUIDE.mdis a before/after migration guide sitting in the census'shandwrittenstratum, whose contract reads "a failing block here is a defect an author can repair". For this document's ❌ blocks that is false, and after this repair all five of its remaining TOLERANT failures are correct documentation. This is a real input to [finding] packages/core/PHASE2_IMPLEMENTATION.md's fenced TypeScript blocks are in no tsc program — a block that has NEVER compiled survived two sweeps, and the gate #15931 proposed would not have caught it #18715's wiring decision, since it is part of what a gate would be asked to hold at zero.packages/spec/DEVELOPMENT_PLAN.md:463-465,packages/spec/ZOD_SCHEMA_AUDIT_REPORT.mdand rootCHANGELOG.md:2289-2290. Left untouched by the dispatch's read-only fence; the seat files these.⛔
packages/spec/package.jsonandpackages/core/package.jsonwere not opened for editing. Route (2) was never needed: it is impossible for two of the three specifiers, since a module that does not exist cannot be declared in anexportsmap.Generated by Claude Code