fix(spec): the protocol 17 → 18 conversion summaries state each decision in words instead of a tracker number (stage 5) - #21568
Conversation
…ion in words instead of a tracker number (stage 5) Text only: the 35 toMajor-18 summaries in conversions/registry.ts that cited a tracker number now say what the cited decision was, or drop a citation the sentence already explained. No id, surface, step, transform or order changes. One @objectstack/spec patch changeset. Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 14 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 8 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 138 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 835137fc4333c4abc146465144903d1df7b98658 && git checkout 835137fc4333c4abc146465144903d1df7b98658
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1ca1eb09727d7769bc605428ad1e6fb62d743f49 9a35e049e5af42d5453da3da41026dd631d937bf && git checkout -B drift-repro 1ca1eb09727d7769bc605428ad1e6fb62d743f49 && git merge --no-ff 9a35e049e5af42d5453da3da41026dd631d937bf
node scripts/docs-audit/affected-docs.mjs --json 1ca1eb09727d7769bc605428ad1e6fb62d743f49
|
Contract reviewServed-tier: ① Derived judgmentsInputs. Read on GitHub through REST: card #20749 (body and all 17 comments, the stage-4 dev report Text only; the accept set is unchanged. The registry diff is 35 hunks and 127 changed lines; every removed and every added line is the string literal of a Public surface. A summary is a data value an author reads. The A2 projection reading is right. The 35 rewritten strings, each against the cited decision. All 35 state the decision truly or drop a citation whose sentence already stated it; none changes the summary's "what moves" clause. Eleven are citation drops with the sentence otherwise unchanged (the ADR-0049 name kept where the opener carried it): #8321, #10414, #17296, #18612, #10054, #19054, #20085, #20161, #20221, #19992, #20321. The other 24 gain words naming the decision.
No surviving quote, no pin. Census and boundary. The stage-4 split listed 35 summaries / 40 ids / 34 cards at ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
ACCEPT — PR #21568 @
|
Part of #20749
Clause-②: no
Stage 5 of the
domain:speclane's share of the runtime-string burn-down (ruling5902360492, form D): the rest of class (b), the protocol 17 → 18 conversion summaries inpackages/spec/src/conversions/registry.ts. Every rewritten summary now states in words what the cited decision was, or drops a citation its sentence already explained. Text only.What changed
field-malformed-scale-precision-removedtoflow-decision-mode-inclusive-explicit. A summary is whatos migrate meta --jsonreports underspecChanges(its chain already runs to protocol 18,CHAIN_TERMINUS_MAJOR), and it becomes the upgrade guide's "Change" column and thetotext ofspec-changes.json'sconverted[]once protocol 18 ships, so an author upgrading metadata reads it.@objectstack/specpatch changeset,Clause-②: no(message text only).Census at the base (A1)
Stage 4's instrument (
convtable.cjs, byte-identical copy, md59b7539067ffc38598172c692de637db5) at basee901c27449(the worktree before any edit): 127 conversions, 35 summaries with ids, 40 id occurrences, 34 distinct cards — stage 4's split unchanged. The toMajor-18 conversion that PR #21547 added carries no id. Under the ~60-card bar, so one stage. The stage-3 census re-run at the same base agrees (class b: 35 messages / 40 ids; nothing else in class b).registry.ts:6551field-malformed-scale-precision-removedregistry.ts:6659record-chatter-position-vocabularyregistry.ts:6777element-input-target-variable-removedregistry.ts:7024element-filter-removedregistry.ts:7177element-form-removedregistry.ts:7356translation-per-app-settings-removedregistry.ts:7356translation-per-app-settings-removedregistry.ts:7610translation-component-submit-label-removedregistry.ts:7782field-column-lists-canonicalizedregistry.ts:7783field-column-lists-canonicalizedregistry.ts:7909metric-filters-removedregistry.ts:8104cube-sub-day-granularities-removedregistry.ts:8237cube-join-sql-and-relationship-removedregistry.ts:8502record-highlights-field-icon-removedregistry.ts:8759page-component-responsive-removedregistry.ts:8860object-grid-default-sort-removedregistry.ts:9047object-grid-resizable-columns-removedregistry.ts:9250object-kanban-quick-add-removedregistry.ts:9634permission-allow-restore-purge-removedregistry.ts:9637permission-allow-restore-purge-removedregistry.ts:9954field-reference-to-aliasregistry.ts:10372hook-timeout-to-timeout-msregistry.ts:10413job-timeout-to-timeout-msregistry.ts:11017api-endpoint-cache-ttl-to-cache-ttl-secondsregistry.ts:11086dashboard-refresh-interval-to-refresh-interval-secondsregistry.ts:11447memory-persistence-auto-save-interval-to-msregistry.ts:11671turso-config-timeout-to-timeout-msregistry.ts:11761view-page-mount-removedregistry.ts:11866list-view-sort-string-clause-to-arrayregistry.ts:11868list-view-sort-string-clause-to-arrayregistry.ts:12366object-tenancy-organization-field-removedregistry.ts:12476view-item-owner-hidden-removedregistry.ts:12620view-overlay-owner-hidden-removedregistry.ts:13214page-component-filter-record-to-rule-arrayregistry.ts:13214page-component-filter-record-to-rule-arrayregistry.ts:13463report-joined-chart-removedregistry.ts:13728form-layout-inline-grid-to-verticalregistry.ts:13884currency-config-precision-removedregistry.ts:13988permission-rls-tags-removedregistry.ts:14128flow-decision-mode-inclusive-explicitProjections (A2)
Neither generator projects a toMajor-18 summary at this base.
build-spec-changes.tsandbuild-upgrade-guide.tsboth loopmajorfromMIGRATION_SUPPORT_FLOOR + 1toPROTOCOL_MAJOR, which are 16 and 17 here (PROTOCOL_VERSION = '17.0.0'), sospec-changes.jsoncarries oneperMajorrecord (16 → 17) and the guide one "Protocol 16 → 17" table.check:generatedreads all 15 artifacts up to date on this head with no regeneration, so no generated file is in the diff. Both projections will pick these summaries up when protocol 18 ships.Delivered: each site, the decision read, the new words (A3)
Every cited card was read through REST with all its comments (30 objectstack cards, objectui#3951, #6206, #6837, #8221). The record column names the comment the decision was read from. Where a summary already said why, the citation is dropped and the sentence kept; where an
(#N, ADR-0049 — …)opener cited both, the card number goes and the ADR stays, as stage 4 did. In thecube-join-sql-and-relationship-removedrow,ALIASstands for the angle-bracket placeholder in the source.field-malformed-scale-precision-removed(:6550)record-chatter-position-vocabulary(:6658)element-input-target-variable-removed(:6778)sourcenames the component id)element-filter-removed(:7025)element-form-removed(:7179)translation-per-app-settings-removed(:7358)settings, a per-app bundle refuses it (settings is a platform key). #19620 ruling B:settingsleaves the translation item too, because the file door and the item door are two authoring surfaces of one app metadata type and accept one shape (ruling 5653315643 (#15178); ruling 5770445203 (#19620))translation-component-submit-label-removed(:7613)element:formretired whole because no renderer for it ever shipped (dead at element grain), which leftsubmitLabelwith no carrier (dev report 5384430470)field-column-lists-canonicalized(:7787)namewins and the grid reader is fixed to read it. #9227:inlineColumnsgets a strict name-keyed element schema (an unknown key is a named rejection at publish, not a blank cell);relatedListColumns, checked in the same pass, takes field-name strings (ruling 5236150020 (objectui#3951); ruling 5315735776 + ACCEPT 5317488979 (#9227))metric-filters-removed(:7916)where, or use an ADR-0021 dataset measure's structuredfilter; a metric's ownsqlis a column reference)cube-sub-day-granularities-removed(:8111)queryDateGranularitycannot advertise them; ADR-0049 prefers removal with no committed roadmap; citation dropped (dev report 5648182389 + landing 5648923185)supports.queryDateGranularityis a record overDateGranularity, which declares day, week, month, quarter, year. Offer the coarsest interval that still answers the question)cube-join-sql-and-relationship-removed(:8244)sqlandrelationshipfrom CubeJoin: the join is derived from the FK relationship and no author-supplied ON clause executes; the addendum adds the D2 strip for persisted artifacts; citation dropped, the sentence already said it (ruling 5725370783 + addendum 5727426171)joins.ALIAS.namealone; the record KEY is the foreign-key field on the base object)record-highlights-field-icon-removed(:8509)page-component-responsive-removed(:8766)page.components[].responsive(ADR-0049, wired into no renderer) and repair the texts that redirected authors to it (ruling 5380752244)object-grid-default-sort-removed(:8868)defaultSort(the strict route per the playbook), completing the objectui-side direction ruling at the producer (ruling 5404972152)object-grid-resizable-columns-removed(:9055)resizableis canonical andresizableColumnsretires now as a tombstone naming it: zero writers, so no window (immediate retirement) (triage direction 5958164933)object-kanban-quick-add-removed(:9258)quickAddleavesobject-kanban(accepted and dropped there); this repo carries the tombstone half (card body (the objectui ruling it executes, option B) + triage 5620331176)permission-allow-restore-purge-removed(:9643)allowRestore/allowPurge, which gate operations that do not exist; #1883 stays open as the M2 anchor, where undelete/purge ship as feature + RBAC in one batch and the keys return with it (card body (#12497); ruling 5421209848 (#1883))restore/purgeoperations they claimed to gate have never existed, so granting the bits delivered nothing; dispatched destructive lifecycle verbs stay denied fail-closed. The keys return with the M2 lifecycle initiative, which builds undelete and purge together with the permission bits that gate them)field-reference-to-alias(:9962)reference, half 2 deletes objectui's legacy fallback arms (ruling 5475017957 + half-1 pointer 5475055291)reference ?? reference_tofallback arms)hook-timeout-to-timeout-ms(:10383)job-timeout-to-timeout-ms(:10424)api-endpoint-cache-ttl-to-cache-ttl-seconds(:11028)dashboard-refresh-interval-to-refresh-interval-seconds(:11097)memory-persistence-auto-save-interval-to-ms(:11458)turso-config-timeout-to-timeout-ms(:11682)view-page-mount-removed(:11772)pagemember and its mount leave the spec under enforce-or-remove (card body (the maintainer ruling it records))pageNamebinding removed (retired rather than finished: the delegating render half was never built, so a page view fell through to the grid branch and drew an empty table; ADR-0049 enforce-or-remove)list-view-sort-string-clause-to-array(:11877)sortis retired, one spelling platform-wide, the array. #17053: the spec slot that produces those documents stops accepting the string objectui now refuses (triage 5620223775 (#17053); ruling 5567944420 (objectui#8221))sortclause becomes the{ field, order }[]array (one sort orthography platform-wide, the array: objectui already refuses the string, so the schema stops minting documents its own consumer refuses)object-tenancy-organization-field-removed(:12377)organizationFieldoff the authorable surface; its one real use stays a platform-internal fact; citation dropped, the sentence already said it (card body (the maintainer ruling it records))tenancy.organizationFieldremoved (ADR-0049 — the stamp-only column declaration was authorable by every application and declared exactly once in the whole protocol, on the platform's own credential table; the divergence moves to a platform-internal table in @objectstack/metadata-core and stops being a knob)view-item-owner-hidden-removed(:12487)hidden, and no per-user scope ever readowner, so a view marked as one user's was listed for everyone)view-overlay-owner-hidden-removed(:12631)hidden: trueoverlay hid no view and anownerscoped none)page-component-filter-record-to-rule-array(:13220)[{ field, operator, value }]rule array wherever the mapping is lossless (flat keys →equalsrules,{ $op: v }→ the mapped operator, AST comparisons → one rule each); a filter carrying$and/$or/$notor any part with no lossless rule spelling is left exactly as stored — reported as a TODO, whichos migrate meta --storedlists — and is not the form its door declares (one filter orthography platform-wide, the rule array; the migration converts only what maps losslessly and names the rest, because flattening a combinator would silently change what a page selects)report-joined-chart-removed(:13477)form-layout-inline-grid-to-vertical(:13742)inline/gridarms: multi-column already exists ascolumnsandinlineis not a record-form layout; citation dropped, the sentence already said it (triage direction 5855767378)currency-config-precision-removed(:13898)currencyConfig.precision: a currency's decimal places are the currency's, not a setting; citation dropped, the sentence already said it (triage 5817146460 (ruling 乙 on #19910 it executes))2baked into parse output went with it; the field-levelprecisionis a total digit count and is untouched)permission-rls-tags-removed(:14002)flow-decision-mode-inclusive-explicit(:14141)mode: 'inclusive'); the migration writes it explicitly for existing nodes so authored behaviour is unchanged (ruling C narrows that promise to sources and artifacts) (ruling 5793803317; ruling C 5863827385)mode:mode: 'inclusive'written explicitly (the traversal became exclusive, first match in declaration order, as mainstream engines treat a decision, and taking every true edge must now be declared; the key keeps the every-true-edge behaviour those nodes had, and the author deletes it where the branches partition)No site was left in place as unclear;
open_questionsis empty.Text only (A4)
Stage 3's AST-skeleton plus string-text tool (
skeleton.cjs, TypeScript 6.0.3; stage 4's copy with only its TypeScript load path changed to this worktree, md53b10ec8a7e6284f19def54d35f001698→32b4630d7d0a532ee26239319269fe91). Leg 1 compares an AST skeleton with every string's text masked (a+chain of string operands reads as one string, so re-wrapping is invisible); leg 2 compares the text of every string group, requiring each changed group to carry a tracker id before and none after, and every other group byte-identical.registry.ts, basee901c27449vs the committed copy at9c1d040145: 1 of 1 SAME, exit 0 — 62656 tokens both sides, 4955 string groups, 35 changed, every changed group carried an id before and carries none after; parse diagnostics 0/0.renameFlowConfigAliasesrenamed → DIFF exit 1;!==flipped to===→ DIFF exit 1; one summary re-split into two+operands → SAME, 0 groups changed, exit 0; thehook.timeoutsurface string (never carried an id) changed → skeleton SAME, text leg VIOLATION, exit 1. No repo file was mutated for the controls.toMajor/surface/ declaration unchanged on all 127, and 0 ids left in any summary.Pins and quotes (A6)
No test asserts a summary, so no pin moves: nothing under
*.test.*reads.summaryoff a conversion (the only summary reads arespec-changes.tsandbuild-upgrade-guide.ts), and every removed id-bearing fragment was searched across the repo. The hits are other files' own prose with their own citations (CHANGELOGs,migrations/registry.tsrationale, docblocks,liveness/*.jsonnotes, test titles such aspermission.test.ts:278, docs prose incontent/docs/permissions/*.mdx), not quotes of a summary.content/docs/**: no quote of a changed summary.skills/**: none.Verification
All builds and tests through
scripts/pm/os-verify-lock.sh(slotissue-20749-s5), eachVERDICT command-exit 0:pnpm --filter @objectstack/spec build, thencheck:generatedon the merged head9a35e049e5: "✓ All 15 generated artifacts are up to date".testscript (vitest run --project local --maxWorkers=2) on9a35e049e5: "Test Files 605 passed (605) / Tests 17904 passed | 1 todo (17905)".test:repo: the 15 repo-project files that read the conversion registry,spec-changesor the guide, "Test Files 15 passed (15) / Tests 221 passed (221)". NOT MEASURED:scripts/build-schemas-check-mode.test.ts(88 cases at about 7 s each, over the foreground cap; it reads only conversion surfaces, which the proof shows unchanged) and the remaining repo-project files; reason: wall clock on a shared box. CI runs them.pnpm --filter @objectstack/spec run typecheckon9a35e049e5: exit 0; "check:test-typecheck: OK — 52 file(s) / 246 error(s) / 135 pinned signature(s) held".pnpm turbo run build --concurrency=2 --filter=./packages/* --filter=./packages/*/*: "Tasks: 71 successful, 71 total", for the gates that read built packages.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths) at9a35e049e5derives 79 commands; each ran with its exit code written to disk before any pipe. Three first exited 3 (PREREQUISITE NOT MET:check:doc-formula-expressions,check:dual-build-cjs-loads,check:lean-entry-closureneed built packages) and exit 0 after the build; the dist-reading gates were re-run after it too.--ran: "✓ dispatch-gates --ran: 79 derived famil(ies) accounted for — 79 run, 0 NOT-MEASURED".pnpm check:doc-authoring(self-test and run): exit 0, "17323 customer-facing string(s) across 1250 spec sources clean"; the sibling-package ledger holds its baseline (packages/specsits outside it, so no ledger change).pnpm check:nul-bytes: exit 0, "no raw ASCII control bytes".--eventpayload:check-changeset-no-major.mjs --base origin/main --eventexit 0 ("✓ LEVEL AXIS: this PR declares clause-②no", declaration lineClause-②: no);check-partof-closing-keyword.mjswithPR_BODYexit 0 ("no Part-of/closing-keyword contradiction");check-adr-0087-registration.mjs --base origin/mainexit 0 ("adds no declared-breaking changeset (1 non-breaking changeset(s) seen)");check-empty-changeset.mjs --base origin/mainexit 0;check-changeset-fixed.mjsexit 0.eslint --no-inline-config --format jsonover the one changed TS file reads 1 file, 0 errors, 0 warnings; the population is read from ESLint's own config (calculateConfigForFileresolves it,isPathIgnoredfalse); invariance:eslint.config.mjsenables no type-aware linting (parserOptions.project/projectServicenull for this file, its header at :327-328 says so), so a string-text edit cannot move an untouched file's verdict. Repo-widepnpm lintis CI's.Acceptance notes
origin/mainwas merged once (9a35e049e5, five commits: fix(runtime)!: refuse the stored-metadata family evaluate shapes and serve write returns at the reader-context seams #21539, fix(metadata-protocol): refuse an org-scoped public form withdrawal a walled posture cannot honour #21473, fix(core): os migrate resume completes a recorded-by run that committed a chunk or used a non-default --chunk-size (#21528) #21554, docs(approvals): reassign TSDoc holds slot addresses; ADR-0042 §2 superseded in part by ADR-0118 D1; SLA checklist expects no actor #21556, fix(metadata-protocol): the object door never lets a container's expansion displace a stored row of the same name (#21510) #21557; spec moved only incontracts/approval-service.tsTSDoc); spec rebuilt,check:generated, the spec test project, typecheck and the gate union re-ran on the merged head. No os-regen deferral was recorded.conversions/registry.ts,spec-changes.jsonor the upgrade guide (all nine open PRs' file lists read just before opening this one).9a35e049e5): non-test 160 → 125 messages, 358 → 318 ids; class (b) is empty. Left for the later stages: class (c) conformance-case notes 58 messages / 68 ids (the#5322selector and the#8934name pin move with their tests), class (f) internal registry rationale 17 / 33, the test strings 1804 / 1920 in 425 files;migrations/registry.ts50 / 217 stays with packages/spec/src: 1,277 comment lines still cite 170 deleted tracker numbers (1,295 sites) — the staged remainder of ruling C+D on #19123, measured by PR #20226 #20234's stage 11. Word-form hits (an id spelled after "PR", "issue" and the like) stay 6, all outside this diff.migrations/registry.ts, comments anywhere, classes (c) and (f), test strings, the.mjsgate scripts. No gate is added or loosened.Generated by Claude Code