Skip to content

fix(spec): os migrate meta guidance for the rest-*, analytics-*, view-*, package-*, object-*, sharing-*, audit-*, flow-* and http-* migration entries states each lesson in words, not tracker numbers (stage 6) - #20536

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-20233-migrate-meta-tracker-free-stage-6
Sep 29, 2026

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #20233
Stage 6: the rest-, analytics-, view-, package-, object-, sharing-, audit-, flow- and http- families.

Clause-②: no

Stage 6 of a staged card. The card stays open for later stages; this PR carries no closing keyword. Text only: no entry id, from / to, conversion or matching logic moves, and the chain rewrites exactly what it rewrote before. One surface moves, under ruling A of the stage-1 ACCEPT (5858839916): it carried two tracker numbers.

What this does

os migrate meta prints every ADR-0087 semantic entry it crosses as one block: ⚠ [protocol N] SURFACE → REPLACEMENT, then why: (the entry's reason) and verify: (its acceptanceCriteria). AGENTS.md's runtime-string rule applies to all of it: 「Runtime strings — refusal prose, prescriptions, anything an author is shown — carry no tracker number (pnpm check:doc-authoring): the lesson goes into the text.」 Form D of ruling C+D on card 19123 (5749154545) sets the shape: the lesson in words, and no number, dead or alive; a cross-repo number is still a tracker number.

This stage covers the nine families rest-, analytics-, view-, package-, object-, sharing-, audit-, flow- and http-: 122 sites → 0 in the three prose fields and 2 → 0 in surface, across 33 entry files. It also takes the two carry-overs the stage-5 record (5880299859) named:

  • 18.api-error-retry-after-unit-in-key: the clause on the ~16 runtime-emitted measurements and ApiError.retryAfter now dates the ruling that decided it — "its 2026-09-05 population ruling" — instead of reading under ruling B's 2026-09-02 date alone.
  • 18.inline-grid-column-currency-scale-refused: the two ruling-record ids and the batch / item numbers are replaced by the rulings' dates and options, the same rewrite stage 5 gave its field- sibling.

Each site now says what the cited ruling, measurement or fix decided. ADR ids stay, and so does Prime Directive #10 in 18.package-manifest-version-grammar-enforced (a rule in AGENTS.md, as stages 2–5 kept #10 / #12). registry.ts, spec-changes.json and docs/protocol-upgrade-guide.md are regenerated from the entries (gen:migration-registry, gen:spec-changes, gen:upgrade-guide), never hand-edited. The pin now holds twenty-seven families.

Census — tracker ids in the author-shown fields

Instrument. The stage-4 / stage-5 TypeScript-AST census, the same script: for each entry object literal under packages/spec/src/migrations/entries/** it evaluates replacement, reason, acceptanceCriteria and (separately) surface, joining string literals with +, and counts # followed by 4 or 5 digits at a word boundary. On base fb386074 it reads the whole tree at 461 sites / 5 surface / 50 short, which is the stage-5 record's after-count. Unevaluable fields: 0. 313 semantic entries.

Controls, same run.

  • Lit: 17.aggregation-node-distinct-retired.ts reads 7 sites (replacement 1, reason 6), before and after.
  • Dark (comment lines): 832 // / docblock lines in entry files carry a tracker id, and none is counted; 832 before and after. Comment lines are the sibling card's surface (the one that owns every comment and docblock line), and this PR touches none (proved below).

Base fb386074: rest- 6 entries, 17 sites (0 / 17 / 0); view- 10, 15 (0 / 13 / 2); analytics- 6, 14 (2 / 12 / 0); audit- 2, 14 (2 / 12 / 0); sharing- 2, 14 (1 / 13 / 0); http- 2, 13 (0 / 13 / 0); object- 7, 13 (1 / 11 / 1); flow- 6, 11 (0 / 11 / 0) plus 2 in surface; package- 6, 11 (0 / 10 / 1). 122 sites (6 / 112 / 4) in 31 of the 47 entries; 91 distinct ids read (82 in this repository, 8 in objectui, 1 hotcrm#), plus five ruling-record comment ids. Short numbers in the nine families: 9 (one kept, the Prime Directive).

After this PR: all nine families 0, surface 0; the seventeen earlier families still 0; whole tree 461 → 339, surface 5 → 3, short 50 → 40 (the two inline- batch numbers included). The PM's rough line count (about 133 sites, about 30 files) is a wider line instrument; the AST reading is 122 in 31 files.

entry sites (replacement / reason / acceptanceCriteria) surface short numbers record ids
17.analytics-query-request-envelope-retired 1 (0 / 1 / 0)
17.audit-log-action-enum-retired 4 (0 / 4 / 0)
17.audit-log-action-restore-retired 10 (2 / 8 / 0)
17.flow-retry-max-retries-required 1 (0 / 1 / 0)
17.http-request-errors-total-retired 7 (0 / 7 / 0)
17.http-server-runtime-vocabulary-retired 6 (0 / 6 / 0)
17.package-uninstall-explicit-all-tenants 3 (0 / 2 / 1) 1
17.rest-server-openapi31-block-removed 2 (0 / 2 / 0)
17.sharing-execution-context-retired 11 (1 / 10 / 0)
17.sharing-rule-recipient-reconcile 3 (0 / 3 / 0)
17.view-filter-rule-value-shaped-by-operator 4 (0 / 3 / 1)
17.view-management-protocol-retired 3 (0 / 2 / 1)
18.analytics-authorable-unknown-keys-refused 3 (0 / 3 / 0)
18.analytics-date-range-array-two-bounds-required 7 (2 / 5 / 0) 1
18.analytics-time-dimension-date-range-vocabulary-closed 3 (0 / 3 / 0) 1
18.api-error-retry-after-unit-in-key 0
18.flow-decision-branch-expression-absent-refused 1 (0 / 1 / 0)
18.flow-decision-edge-branching-first-match 1 (0 / 1 / 0)
18.flow-edge-condition-evaluated-slot-source-required 4 (0 / 4 / 0) 2 1
18.flow-predicate-slot-blank-string-refused 4 (0 / 4 / 0) 1
18.inline-grid-column-currency-scale-refused 0 2 2
18.object-block-sort-item-array 3 (0 / 3 / 0) 1
18.object-grid-data-view-data-converged 4 (0 / 3 / 1)
18.object-grid-default-filters-rule-array 2 (0 / 2 / 0)
18.object-index-unknown-keys-refused 4 (1 / 3 / 0)
18.package-api-contracts-unmounted-entries-retired 3 (0 / 3 / 0) 1
18.package-install-request-unknown-keys-refused 0 1 1
18.package-rollback-response-retired 5 (0 / 5 / 0)
18.rest-api-endpoint-handler-status-retired 7 (0 / 7 / 0) 1
18.rest-api-plugin-durations-unit-in-key 3 (0 / 3 / 0) 1
18.rest-server-config-dead-keys-retired 5 (0 / 5 / 0)
18.view-filter-rule-absent-value-refused 2 (0 / 2 / 0)
18.view-filter-rule-scalar-operator-array-refused 4 (0 / 4 / 0)
18.view-overlay-options-bag-judged 0
18.view-pagination-page-size-default-50 2 (0 / 2 / 0)
total, 35 entries 122 (6 / 112 / 4) 2 10 (0 kept) 5

The fourteen entries of these families that carried no number are untouched: analytics-cube-public-default-visible-enforced, analytics-query-request-format-retired, flow-node-config-required-keys-refused, object-grid-default-sort-retired, object-kanban-quick-add-retired, object-tenancy-organization-field-retired, package-manifest-version-grammar-enforced (its one short number is the kept Prime Directive), package-version-row-semver-2-0-0, rest-api-config-dead-keys-retired, rest-api-documentation-version-retired (the new entry from the landed rest- change: its prose was read and is clean), view-filter-rule-operator-input-canonical, view-item-owner-hidden-retired, view-overlay-judged-by-viewkind-arm, view-overlay-owner-hidden-retired. Four of the 35 changed entries carried no four- or five-digit id: view-overlay-options-bag-judged (a provenance-only acknowledgement quote), package-install-request-unknown-keys-refused (a batch number and a ruling-record id) and the two carry-overs.

Text only — proved by a base-vs-head AST comparison

For every entry file this PR changes, both versions (fb386074 and the head) are parsed and compared: every import declaration; every property other than the three prose fields, by evaluated value (so id, from / to and any matcher); every comment token in the file; and the code skeleton, token by token with each run of joined string literals collapsed to one. surface is allowed to differ only where the base value carried a tracker id and the head value carries none. 35 files compared, 0 with a non-prose change; one note, the ruling-A surface of 18.flow-edge-condition-evaluated-slot-source-required. The instrument is shown able to fail first: on an in-memory copy it reports DETECTED for a mutated id, a mutated comment, a mutated surface whose base carried no tracker id, a mutated code token and a mutated import, and stays dark on a prose-only mutation. So none of the sibling card's comment lines moved, and no entry's identity or matching moved.

registry.ts, compared the same way: comment tokens, imports and code skeleton identical; all 1,572 non-prose properties identical by value (container literals compared through their children); exactly the 35 changed ids differ; and all 313 head registry entries equal the head entry files on surface / replacement / reason / acceptanceCriteria.

Every citation read, and what the text now says

Each cited id was read with a single-card REST read (body plus the ruling, measurement or landing comments), resolved against the repository its sentence names: 82 in this repository and 8 in objectstack-ai/objectui (one bare id resolves there: the sort ruling's consumer change 8758 is "objectui PR" in its sentence). The five ruling-record comment ids were read by id. hotcrm#1555 answers 403 to this session and is rewritten from what main records. Ids are in code spans so this body posts no cross-references. 8 of this repository's ids answer 404 on the issues endpoint and again on the pulls endpoint (6206, 6239, 6511, 6523, 10004, 14369, 14691, 17124; control 6209 answers 200); their sentences are rewritten from what main records, listed in Acceptance notes.

rest- (14 ids)

cited what it decided (read) how the text now carries it
3197 An audit: several event / subscription / connector webhook enums are schema-only, declared with no runtime consumer. "the declared-but-unconsumed shape an earlier audit found in the connector webhook and event enums one layer up"
4579 This retirement's own card (openApi31 declared, never enforced). trailing id dropped; "(the openApi31 precedent)"
13823 Maintainer, 2026-09-01: remove handlerStatus with a tombstone; enforce excluded; the class direction recorded for two sibling cards. "maintainer ruling of 2026-09-01 on this key: remove it with a tombstone; enforce excluded"; trailing id dropped
5384 ApiEndpointSchema was still an open object after api became a registered metadata type; closed strictly. "the same endpoint vocabulary whose ApiEndpointSchema had already been closed strictly once api became a registered metadata type"
13808 (PR) A factual sweep of the automation skill; one corrected sentence taught handlerStatus as working machinery. "this finding came out of correcting that skill sentence, in a factual sweep of the automation skill"
3950 (PR) The precedent that an exported value schema with no consumer reads as a capability, so it leaves with its key. "an exported value schema with no consumer reads as a capability, so it leaves with its key"
13612, 13613 The unbound branded identifier schemas; EventNameSchema's binding schemas with no runtime consumer. "two sibling ADR-0049 findings (the unbound branded identifier schemas and the event-name schema no runtime reads; not ruled by it)"
14478, 15677 Maintainer ruling B on duration units (2026-09-02), its population widened 2026-09-05; the api/ stack of that ruling. the stage-3 wording, naming both dates; trailing ids dropped
14369 404 — see Acceptance notes. "The liveness census that enrolled the four RestServerConfig sub-objects"
11984 normalizeConfig cast the four sub-objects instead of parsing them; it parses them since. "(which parses them, rather than casting them, since an earlier fix)"
14796 A closed-set sweep of the cloud repository for the 15 dead keys: zero hits. "A closed-set sweep of the cloud repository at 9b6abe0f2fd5: zero hits"
14691 404 — this retirement's own card. trailing id dropped

analytics- (10 ids)

cited what it decided (read) how the text now carries it
3891 The degraded analytics shim (the fallback serving /analytics/query with no analytics service installed) dropped the caller's identity and the contract's where filter at its door. "the retired degraded analytics shim (the fallback that answered /analytics/query when no analytics service was installed, and dropped the caller's identity and its where filter at the door)"
4001 The unknown-key strictness campaign: silent stripping of undeclared keys ends as the default, schema family by schema family. "The unknown-key strictness campaign (the sweep that ended silent stripping of undeclared keys as the default, one schema family at a time), its data/ batch"
3878 One URL, two request bodies (the shim's envelope vs the bare query); the envelope dialect was retired. "strict since the degraded shim's envelope dialect was retired (one URL, one request body)"
10414 MetricSchema.filters was authorable with zero consumers; removed. "removed later in this major, because nothing ever read it: metric-filters-removed"
17598 Maintainer ruling A, 2026-09-12, re-affirmed 2026-09-13: the array arm refuses anything but exactly two string bounds. "Maintainer ruling A of 2026-09-12, re-affirmed 2026-09-13, which tightened the array arm to exactly two string bounds"
16322 The driver half of the closed preset vocabulary; its migration table is the vocabulary entry's, unchanged (single day as the same date twice). "the shipped migration table for the closed preset vocabulary"; "in a driver change of their own"
17593 (PR) All four analytics faces read the array arm through one rule and refuse the rest with the ADR-0112 envelope. "since the fix that made them read the array arm one way"; "The fix that followed made all four faces refuse it"; "Since that fix"
17124 404 — see Acceptance notes. "a measurement of one authored document on each face found what that bought"
16041 Maintainer, 2026-09-06, option A (contract first): the string arm closes to the declared preset vocabulary. "Maintainer ruling of 2026-09-06 on the analytics date-range string (option A — contract first)"
4614 The preset list, once three copies (spec, objectui, docs), became one source of truth. "since the dashboard date filter's three copies of the list were folded into it"

view- (10 ids)

cited what it decided (read) how the text now carries it
5869, 6209 (PR) A scalar comparand on in / not_in answered 500; now a named 400 INVALID_FILTER. "An earlier fix closed the RUNTIME half"; the trailing (5869) in acceptanceCriteria dropped
5685 The ordering operators' comparand was widened to the strings the platform itself produces (a schema stricter than the runtime was the wrong side). "an earlier fix already settled the opposite error (the ordering operators' comparand widened to the strings the platform itself produces)"
5948 The issue asking what GET /ui/view/:object/:type answers, and its 2026-08-07 ruling, both read GetViewResponseSchema. "The issue asking what GET /ui/view/:object/:type answers AND its 2026-08-07 maintainer ruling"; "the shapes that ruling meant"
6239 404 — this removal's own change (recorded in the client and spec CHANGELOGs). trailing id dropped
19751, 19514 The absent-value and scalar-array findings (this and its sibling entry's own cards). leading ids dropped
6227 ViewFilterRuleSchema.value shaped by its operator (the view-filter-rule-value-shaped-by-operator entry). "since the value was first shaped by its operator"; "from then until this change"
objectui#9050 Maintainer ruling C′, 2026-09-20: the protocol is the only refusal set; render time never throws on a protocol-valid document. "the maintainer's ruling C-prime of 2026-09-20 on objectui's render-time filter converter — the protocol is the only refusal set, so a document it accepts never throws at render time"; the lesson quote 「the differences are the protocol's to close」 kept verbatim
objectui#9853 Maintainer, 2026-09-24: the display default page size is 50, declared once in the protocol; objectui reads the spec default and never hardcodes it. "the maintainer's ruling of 2026-09-24 set the platform display page size to 50, declared once in the protocol"; "(an earlier ruling on the grid's page size, which the page-size ruling restated)"
(no id) view-overlay-options-bag-judged Maintainer, 2026-09-24 (objectui's overlay-options card), option A: judge each options.KIND at the door. 「其他同意」 replaced by "the maintainer's ruling of 2026-09-24"

package- (8 ids and one ruling record)

cited what it decided (read) how the text now carries it
7705, 7780 Uninstall left orphaned rows (repaired); measured there: an org-less uninstall deleted every organization's rows. "measured at 5 of 5 deleted, including a foreign org's, while uninstall's orphaned-row defect was being repaired"; "exactly as the orphaned-row repair left it"
#12 (short) Not a tracker id: rest-requireauth-default-flip lived in protocol 12. "(protocol 12)", the spelling four sibling entries use
19116 Maintainer, 2026-09-23, option A: retire the three contract-map entries naming paths nothing mounts. "Maintainer ruling of 2026-09-23 (option A: retire the three contract-map entries that name paths nothing mounts)"
18604 The measurement on one HttpDispatcher over a real SchemaRegistry. the measurement was already in the sentence; the id is dropped
18058 installPackage rebound onto the serving POST /api/v1/packages. "rebound by an earlier fix onto the serving POST /api/v1/packages"
5856869656 (record) Maintainer, 2026-09-27, option A: the wrapped install form refuses an unknown top-level key by name. "the maintainer's ruling of 2026-09-27, option A: the wrapped form refuses an unknown top-level key by name"
12038 Maintainer, 2026-08-27, sub-question 3A: retire the false rollback declaration first, then author the true one. "Maintainer ruling of 2026-08-27 on the client SDK's unbound response contracts, sub-question 3A: retire this false declaration first, then author the true one"; "the ruling's own survey"
11925 Typed the SDK's un-annotated return values, keeping compile-time guards against a wrong-contract substitution. "the change that typed the SDK's un-annotated return values left a compile-time guard"; "that negative guard"
3877 Response bodies are never checked against the schemas that declare them. "the hazard of response bodies never checked against the schemas that declare them, realised in the opposite direction"

object- (11 ids)

cited what it decided (read) how the text now carries it
objectui#8221 Maintainer, 2026-09-07, option B: the legacy string sort clause retired, one spelling (the array); its fourth item routes the ComponentPropsMap pull-back here. "the maintainer's ruling of 2026-09-07 (option B) retired the legacy string sort clause"; "One item of that ruling"; the item's quote kept verbatim
8758 (objectui PR) The consumer half: the string arm dropped from convertSortToQueryParams. "the objectui change that drops the string arm from convertSortToQueryParams"
7751 Maintainer, 2026-08-12, direction A: the object-* block family's props schemas enter ComponentPropsMap. "a read-point record from the change that brought the object-* blocks into ComponentPropsMap (the maintainer's ruling of 2026-08-12)"
objectui#6207 Found by objectui's declared-arm parity gate: two spec authorities disagreed on data's kind. Ruled 2026-08-25, option A. "(contract-vs-contract, found by objectui's declared-arm parity gate)"; "The maintainer's ruling of 2026-08-25 (option A)"; "closes the objectui finding that the two authorities disagreed"
objectui#5090 The grid's registry declaration of data was aligned to ViewData. "the authority objectui aligned the grid's registry declaration to"
objectui#4648 Its deprecated-alias carve-out: object-grid's deprecated spellings (staticData among them) are not published as authoring surface. "the deprecated staticData shortcut that objectui's deprecated-alias carve-out already refuses to publish as authoring surface"
19514, objectui#9050 As in view-. as in view-
objectui#4772 The console's index fallback editor converged onto IndexSchema, dropping where. "removed when objectui converged that editor onto IndexSchema"; "objectui then converged that editor"
4001 As in analytics-. "The unknown-key strictness campaign held this site open" (its internal batch and site numbers dropped)
5114 The console's filter save answered 422: a strict schema refused a key the console itself writes. "a measured risk, the kind that had already made a console save answer 422 (a strict schema refusing a key the console itself writes)"

sharing- (11 ids)

cited what it decided (read) how the text now carries it
6206 404 — see Acceptance notes. "completing the maintainer's ruling of 2026-08-07 on the share-link context (enforcement adjudicates on the WHOLE envelope, never a per-site subset)"
6430, 6511 The share-link enforcement path moved onto the full context under that ruling (6511 answers 404). "the share-link twin, which that same ruling moved onto the whole context"
6523, 7068 (PR) The sharing, approval and report contracts converged onto the full envelope (6523 answers 404). "the envelope the sharing, approval and report contracts have declared since they converged onto it"; "One change converged the contracts"
7140 (PR), 7206 (PR), 7070 The four implementations re-annotated (sharing and audit, then approvals and reports); the split that deferred the type's deletion. "two more re-annotated the four implementations (sharing and audit, then approvals and reports)"; "the deletion that split had deferred"
7218 This retirement's own card. trailing ids dropped
1878 The metadata property liveness audit: security properties parsed but never enforced. "The change came out of the metadata property liveness audit, which found security properties parsed but never enforced"
6350 The stock reconciliation of the v17 train's breaking changesets, which backfilled this entry. "registered late, by the stock reconciliation that compared the breaking changesets already on the v17 release train against this ledger"

audit- (8 ids)

cited what it decided (read) how the text now carries it
7675 Maintainer, 2026-08-12: two halves — build the cheap writers, retire the enum values with no feature; principle recorded 「空 widget + 永远查不到东西的过滤器是可见产品缺陷;审计面宁窄勿谎」 (kept verbatim, it is the lesson). "Maintainer ruling 2026-08-12 on the audit log's writerless actions"; "that ruling's own survey"
8144, 8145 The login / logout writers on the auth session hooks; config_change from the settings service. "(login / logout on the auth session hooks, config_change from the settings service)"
8147, 8315 The two retirements' own cards. trailing ids dropped; "(triage 2026-08-13)" kept
1883, 3146 The undelete / purge permission lifecycle and the soft-delete recycle bin: both open, held, not declined. "(an undelete / purge permission lifecycle and a soft-delete recycle bin, neither built yet)"; "both held open, not declined"
8011 A credential-storage audit had to re-measure two "hashed at rest" comments; resolved by making the declaration cite its mechanism. "(the shape a credential-storage audit had to settle by re-measuring two "hashed at rest" comments)"

flow- (11 ids and two ruling records)

cited what it decided (read) how the text now carries it
4247 maxRetries had two defaults (schema 0, engine 3). the measurement was already in the sentence; the id is dropped
19961 This refusal's own card. leading id dropped
hotcrm#1555 403 — see Acceptance notes. "a CRM application's lead-conversion flow rendered a refusal screen AND ran the conversion in one execution"
17322, 17495 (in surface) The node slot rebound to the edge door's rule at registerFlow, then at objectstack validate. "The node slot joined this entry with the two later changes that rebound AutomationEngine.registerFlow and objectstack validate to the edge door's own rule"
15807, 15430, 15662 The evaluated-slot rule: an ast-only envelope no engine can evaluate refused; a non-string node predicate refused at registration rather than answered a silent false; carried to the edge. "The evaluated-slot rule, carried to the edge condition — the line that first refused an ast-only envelope no engine can evaluate, and refused a non-string node predicate at registration instead of letting the evaluator answer it a silent false"
5550509137 (record) 2026-09-05: an ast-only envelope driven through AutomationEngine.evaluateCondition answers false. "(measured on 2026-09-05 by driving an ast-only envelope through AutomationEngine.evaluateCondition directly)"
17493, 5651023407 (record) Maintainer ruling A, 2026-09-13: the two sibling predicate slots refuse a blank string at authoring. "Maintainer ruling A of 2026-09-13: the two sibling predicate slots refuse a blank string at authoring"
15572 Its pin had held the blank admission correct because parser and evaluator agreed. "An earlier fix had pinned that admission as correct"
17322, 15811 The structural config.condition and every evaluated source refuse a blank. "after the structural config.condition and a blank evaluated source"

http- (11 ids)

cited what it decided (read) how the text now carries it
9650, 9835, 9834, 10004 The request counter, then the latency histogram, moved to the transport through the response-observing hook (10004 answers 404). "(the request counter, then the latency histogram, both through the response-observing hook the transport was given)"
5122, 3977 The origin cards of the two named sibling entries. named by those entries' ids, which the sentence already carried
9834, 5295 This retirement's own cards. trailing ids dropped
4938 The CONFIG half of system/http-server.zod.ts removed. "The first removed the CONFIG half"; "the config half's removal in this very file"
4834, 4988, 5055 The dynamic plugin-loading family, the ui/ interaction configs, the widget / i18n shapes — each removed by route 3. "the earlier removals of the dynamic plugin-loading family, the ui/ interaction configs and the widget / i18n shapes"

Beyond the four- and five-digit regex. Nine decision-batch numbers (#27, #43, #57, #77, #117, #215, #217, #218, #227), their item numbers, the campaign's internal batch and site numbers, batch adjudication batch 4, 「五问一批」 and "C′ item 1" were dropped; each sentence now carries the ruling's date and content. The provenance-only acknowledgements 「同意」 (×2), 「其他同意」 (×2), 「217 同意」, 「其他接受」 and 「9853 默认页大小改为50」 (the ruling's content, 50, is stated in words; the quote itself carried a tracker number) were replaced by the ruling's date and content. The lesson-bearing quotes are kept verbatim: 「the differences are the protocol's to close」 (×2), the sort ruling's fourth item, 「every other operator takes a scalar」, 「lowers to a deep-equality comparand」, 「persistViewPatch 只存 patch,不存 merged base」 and the audit ruling's 原则记录.

Pin — widened, not weakened

packages/cli/test/migrate-meta-engine-guidance.test.ts: COVERED_PREFIXES 17 → 27 (rest-, analytics-, view-, package-, object-, sharing-, audit-, flow-, http-, and inline- for the carry-over entry, the inline- family's only entry, now tracker-free); package- selects no packages- entry. REWRITTEN 113 → 147: the 34 ids this stage rewrote for the first time (the 33 nine-family entries plus inline-grid-column-currency-scale-refused; api-error-retry-after-unit-in-key was already listed). The header comment names the new families; the three it blocks and every expect are textually unchanged.

Ablation, from committed HEAD 472ee29b82, one lock turn (scripts/ablation-replace.mjs wrap mode, a restore trap by absolute path with a blob check, scripts/ablation-dist-preflight.mjs): registry.ts, http-server-runtime-vocabulary-retired's reason, anchor behind it, vocabulary second. ADR-0049. → behind it, vocabulary second. ADR-0049, #5295. (anchor 1 → 0, replacement 0 → 1, blob 06c06741 → 702e7370). Mutate leg: spec build exit 0; the marker in 4 dist files; the pin RED, 1 failed | 2 passed: http-server-runtime-vocabulary-retired: the printed guidance cites a tracker id: expected '#5295' to be undefined. Restore proven by the tool (blob == HEAD 06c06741, git diff HEAD empty). Restore leg: spec build exit 0; the marker absent from all 224 dist files with the tree clean; the pin GREEN, 3 passed; whole tree 0 dirty paths.

No other test pins a removed number: on main, the tests naming any of the 35 entry ids (sys-audit-log-retired-actions, plugin-rest-api.handler-status-retirement, rest-api-config-dead-keys-retirement, inline-grid-column-currency-scale-refused, component-object-grid-default-filters.pin, view-overlay-owner-hidden-retirement, and two that name them in passing) assert ids, surfaces and prescriptions this PR does not move, not the prose it rewrites.

Generated artifacts

  • registry.ts: 313 semantic, 232 retired-key, 206 retired-def; exactly the 35 ids differ (see the AST comparison above).
  • spec-changes.json and docs/protocol-upgrade-guide.md: only the protocol-17 entries appear in them, as the generators project; every changed line is a fragment of a changed entry's field.
  • .changeset/20233-rest-analytics-view-package-object-sharing-audit-flow-http-migration-guidance-tracker-free.md: '@objectstack/spec': patch, Clause-②: no.

Verification (head 472ee29b82)

Every heavy run through scripts/pm/os-verify-lock.sh, each exit code written to disk before it was read.

  • Build: turbo run build --concurrency=2 --filter='@objectstack/cli^...' → Tasks: 58 successful, 58 total (VERDICT command-exit 0); plus the 10 packages outside that closure for the dual-build gate → Tasks: 68 successful, 68 total.
  • Pin + neighbour: pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/migrate-meta-engine-guidance.test.ts test/migrate-meta-default-range.test.ts → Test Files 2 passed (2), Tests 10 passed | 1 skipped (the default-range file's own skipIf).
  • CLI unit (the tests that read the registry or spec-changes.json): spec-release-changes, meta.stored-flags, doctor-deprecation-hint-commands, vitest-tiers-partition → Test Files 4 passed (4), Tests 48 passed (48).
  • Spec: --project local → Test Files 573 passed (573), Tests 16835 passed | 1 todo; --project repo → Test Files 39 passed (39), Tests 701 passed (701); src/migrations/migrations.test.ts alone → Tests 150 passed (150).
  • Typecheck: pnpm --filter @objectstack/spec typecheck exit 0 (test layer 53 files / 251 errors held); pnpm --filter @objectstack/cli typecheck exit 0 (3 files / 28 errors held).
  • Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 89 families over this diff; all 89 run, all exit 0; --ran → "89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN". Among them: check:doc-authoring ("16759 customer-facing string(s) across 1172 spec sources clean"), check:generated ("All 15 generated artifacts are up to date"), check:migration-registry ("registry.ts is current (313 semantic, 232 retired-key, 206 retired-def)"), check:spec-changes, check:upgrade-guide, check:issue-citations ("no issue citations added"), check:org-identifier, check:nul-bytes, check:api-surface, check:authorable-surface, check:dual-build-cjs-loads (104 require entry points across 66 packages load), check:type-check-debt, check:adr-0087-registration, check:changeset-no-major, check:empty-changeset.
  • Lint, a proven narrowing: eslint --no-inline-config --format json over the 37 changed .ts files → 37 files, 0 errors, 0 warnings, no file-ignored notice. Population read from eslint.config.mjs (**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus NEVER_LINTED); invariance: the config enables no type-aware linting (no parserOptions.project, no typed rules), so this diff cannot move any untouched file's verdict. The full pnpm lint is CI's.
  • Mergeability: origin/main is 1378ec7c, three commits past the base, none touching the migration ledger or its projections; a driver-free bare-clone merge-tree --write-tree of the head against it exits 0 with no conflicted path. registry.ts is shared with open PRs 20504, 20460 and 20458, ordinary concurrency; no open PR touches any of the 35 entry files or the pin.

Acceptance notes

404 and 403 ids, rewritten from what main records.

  • 6206 (the share-link ruling of 2026-08-07): packages/core/src/security/assemble-execution-context.ts (the share-link copies omitted accessible_org_ids; both surfaces converted to pass the whole envelope) and packages/plugins/plugin-approvals/CHANGELOG.md ("applying the ... ruling — enforcement adjudicates on the whole envelope, never a per-site subset").
  • 6523 / 6511: the same CHANGELOG ("converged 36 contract signatures onto the complete resolveAuthzContext envelope"); 6430 (200) names the share-link half.
  • 6239: packages/client/CHANGELOG.md records it as this removal itself (retire ViewProtocol's five viewId-addressed methods); dropped.
  • 8758 as a bare id: its sentence names objectui, and objectui#8758 answers 200 (the string sort clause retired).
  • 10004: packages/observability/src/semconv.ts and the observability CHANGELOG pair it with 9834 as the histogram's move to the transport seam.
  • 14369: docs/qa/platform-checklist/areas/api-backend.json ("the liveness census that found the block read by nothing") and the 14640 changeset (it enrolled four of the five sub-objects). 14691: the same file records it as this retirement; dropped.
  • 17124: .changeset/17124-daterange-array-arm-arity.md records the measurement (one authored document, four faces, three readings).
  • hotcrm#1555 (403 cross-repo): .changeset/15429-decision-edge-branching-first-match.md records the case and the node (lead_conversion.decision_duplicate).

Observations, not filed.

  • Carrier: this card's later stages · 339 prose-field sites, 40 short numbers and 3 surface sites remain in the other families (the largest: actor- 13, hot- 12, external- 11, query- 11, delete- 10, stack- 10); stack- and turso- have entries in open PRs. The pin file keeps its stage-1 name while holding twenty-seven families.
  • Carrier: the sibling card for comment and docblock lines · 832 comment lines in entry files still cite tracker ids (unchanged), including the header comments of 18.view-pagination-page-size-default-50.ts, 18.view-overlay-options-bag-judged.ts, 18.flow-decision-edge-branching-first-match.ts (hotcrm#1555) and 18.analytics-authorable-unknown-keys-refused.ts.

Implemented-by: claude/issue-20233-migrate-meta-tracker-free-stage-6 · domain:spec seat 4 dispatch, session session_01ARcDurZ5j34RdqsGgc4jgH.


Generated by Claude Code

…t tracker numbers

The reason / replacement / acceptanceCriteria text (and one surface) of the
rest-, analytics-, view-, package-, object-, sharing-, audit-, flow- and
http- ADR-0087 semantic entries, plus the two carry-overs from stage 5
(api-error-retry-after-unit-in-key names its 2026-09-05 population ruling;
inline-grid-column-currency-scale-refused drops the ruling-record ids and
batch numbers its field sibling already dropped). Text only.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
… holds the stage-6 families

registry.ts, spec-changes.json and docs/protocol-upgrade-guide.md are
regenerated by their generators from the rewritten entries. The
os migrate meta guidance pin covers rest-, analytics-, view-, package-,
object-, sharing-, audit-, flow-, http- and inline-, and its REWRITTEN
floor lists the 34 entries this stage rewrote for the first time.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 4 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/spec-changes.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via getView (sdk, the bare tail of client method meta.getView, bound to GET /api/v1/ui/view/:object/:type), meta.getView (sdk, the route ledger binds it to GET /api/v1/ui/view/:object/:type, selected by route anchor /ui/view/:object/:type))
  • content/docs/api/metadata-api.mdx (via /ui/view/:object/:type (route, a path literal in reason; a path literal in semantic))
  • content/docs/api/plugin-endpoints.mdx (via /ui/view/:object/:type (route, a path literal in reason; a path literal in semantic))
  • content/docs/kernel/contracts/metadata-service.mdx (via getView (sdk, the bare tail of client method meta.getView, bound to GET /api/v1/ui/view/:object/:type))
  • content/docs/kernel/services-checklist.mdx (via getView (sdk, the bare tail of client method meta.getView, bound to GET /api/v1/ui/view/:object/:type), /ui/view/:object/:type (route, a path literal in reason; a path literal in semantic))
  • content/docs/protocol/objectui/concept.mdx (via /ui/view/:object/:type (route, a path literal in reason; a path literal in semantic))

⛔ 1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-0.mdx (via getView (sdk, the bare tail of client method meta.getView, bound to GET /api/v1/ui/view/:object/:type), meta.getView (sdk, the route ledger binds it to GET /api/v1/ui/view/:object/:type, selected by route anchor /ui/view/:object/:type))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/spec-changes.json) — pages documenting those are invisible to this run
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 137 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 31d281d3b2b855a7c7d00e48d2ac2fb22aa5c84b → packageMentionDocs.

Which tree this was computed on

This run read content/docs from f67b7d8098ead2d4094c185262977c70d4d179b3 — the merge of head 472ee29b8293041df4664be19fd38ab1a068c136 into base 31d281d3b2b855a7c7d00e48d2ac2fb22aa5c84b, 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 f67b7d8098ead2d4094c185262977c70d4d179b3 && git checkout f67b7d8098ead2d4094c185262977c70d4d179b3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 31d281d3b2b855a7c7d00e48d2ac2fb22aa5c84b 472ee29b8293041df4664be19fd38ab1a068c136 && git checkout -B drift-repro 31d281d3b2b855a7c7d00e48d2ac2fb22aa5c84b && git merge --no-ff 472ee29b8293041df4664be19fd38ab1a068c136

node scripts/docs-audit/affected-docs.mjs --json 31d281d3b2b855a7c7d00e48d2ac2fb22aa5c84b

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 472ee29b8293041df4664be19fd38ab1a068c136
Local-runs: none

Head unmoved across the review (re-read at the end: same sha, open, draft; mergeable_state read blocked first, unknown while recomputing at the last read). Merge base fb386074 (the landed $empty change); origin/main is 31d281d3, four commits past it (12 paths moved on main, none under the migration ledger, its projections or the pin — three unrelated changesets only). Inputs: card #20233 (body + all 23 comments), PR #20536 (body, 40-file list, net diff against main at this head — the API diff and git diff fb386074..472ee29b name the same 40 files, +498/−310), the head's check-runs, plus single REST reads of every id the base prose cited and of the ruling-record comments by id. Read-only throughout: git archive extracts of base and head parsed by my own tokenising and census instruments; nothing built, run or re-run. The record's shape is read from contractReviewRecordLines in scripts/pm/record-recognisers.mjs on main.

① Derived judgments

  1. Text only — holds, mechanically. For each of the 35 entry files that differ, base vs head parsed and compared: every import declaration identical; every // / /* */ comment token identical; every property other than reason / replacement / acceptanceCriteria identical by evaluated value (id, from / to, every matcher); the code skeleton with joined-string runs collapsed identical; the property-key sequence identical. 35 files compared, 0 with a non-prose change. Only the prose fields' evaluated values differ (reason in 35, replacement in 4, acceptanceCriteria in 4). The one allowed surface move is 18.flow-edge-condition-evaluated-slot-source-required (base carried #17322 and #17495; head carries none and changes nothing else in that value) — the instrument's only note, so ruling A 5858839916 had exactly one site here. The instrument fails first on an in-memory copy: DETECTED for a mutated id, a mutated comment, a mutated surface whose base carried no tracker id, a mutated code token and a mutated import; dark on a prose-only edit and on a re-split string run. The 35 files are exactly the PR's entry files (33 in the nine families plus the two carry-overs); the fourteen nine-family entries that carried no number (analytics-cube-public-default-visible-enforced, analytics-query-request-format-retired, flow-node-config-required-keys-refused, object-grid-default-sort-retired, object-kanban-quick-add-retired, object-tenancy-organization-field-retired, package-manifest-version-grammar-enforced, package-version-row-semver-2-0-0, rest-api-config-dead-keys-retired, rest-api-documentation-version-retired, view-filter-rule-operator-input-canonical, view-item-owner-hidden-retired, view-overlay-judged-by-viewkind-arm, view-overlay-owner-hidden-retired) read 0 on base and are absent from the file list; no entry file outside the 35 differs; no turso-, stack-, cube- or data__ file is touched, and no file of [finding] runtime warnings outside the migration ledger print tracker numbers to authors and operators: the AutomationEngine resumeAuthority boot warning (#3801 / #5561 / #3823) and two objectql data-event warnings (#4639 / #4626) #20513's runtime-string family. A head-prose scan of the nine families and inline- for objectui# / hotcrm# / framework# / cloud#, issue / card / PR / batch / record / item + number, any run of six or more digits and any #N finds exactly one token, the kept Prime Directive #10 (base carried PR #17593 ×3, PR #8758, PR #6209, PR #6511 / #7068 / #7140 / #7206, Card #19961 / #15807 / #17493, batch #117 / #215 / #217 / #218 / #227 and the record ids 5550509137, 5651023407, 5791803339, 5805782503, 5856869656, all gone). So none of 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 comment lines moved (832 comment lines with a tracker id on both sides, comment tokens byte-identical), and no entry's identity or matching moved.
  2. Truth of the rewrites — holds; no lesson lost, softened or overstated. Read against single REST reads of every id the base prose carried (83 bare, 7 objectui#, hotcrm#1555; 9 of the bare answer 404 on the issues and pulls endpoints — 6206, 6239, 6511, 6523, 8758, 10004, 14369, 14691, 17124, the same set the dev names — and hotcrm#1555 403; the bare 8758 sits in a sentence that names objectui, where objectui#8758 answers 200: the PR that dropped the string arm from convertSortToQueryParams), the five ruling-record comments by id, the population ruling 5548763981, and main's own files:
    • rest- (17): #13823's ruling 5494755488 (maintainer 2026-09-01 「同意」, batch chore(deps)(deps): bump zod from 3.25.76 to 4.3.5 #27: remove handlerStatus with a tombstone, enforce excluded, the class direction recorded for #13612 / #13613 without ruling them) → "maintainer ruling of 2026-09-01 on this key: remove it with a tombstone; enforce excluded" and "two sibling ADR-0049 findings (the unbound branded identifier schemas and the event-name schema no runtime reads; not ruled by it)" TRUE; #5384 (ApiEndpointSchema still an open z.object after #5312 registered api as a metadata type; later closed) → "whose ApiEndpointSchema had already been closed strictly once api became a registered metadata type" TRUE; #3950 (an exported schema with no consumer is read as a capability) TRUE; #3197 (schema-only connector webhook / event enums) → "the declared-but-unconsumed shape an earlier audit found in the connector webhook and event enums one layer up" TRUE; #4579 is this retirement's own card (ruled remove 2026-08-02), dropped; #14478 ruling B 5518649320 (2026-09-02) and the population ruling 5548763981 (batch Release version 0.1.x for ObjectStack Protocol packages #43, 2026-09-05: every authored and every runtime-emitted duration, exempt by declaration on the schema — EpochMs, .meta({ externalVocabulary })) → the two-date wording TRUE; #14369 (404) → the 14640 changeset ("[finding] Ten declared RestServerConfig keys are normalized by RestServer and read by nothing — routes.* entirely, crud.patterns / objectParamStyle, metadata.cacheTtl / endpoints.schema, batch.defaultAtomic / operations.upsertMany (ADR-0049 enforce-or-remove candidates) #14369 enrolled four of the five RestServerConfig sub-objects") and api-backend.json:2425 → "The liveness census that enrolled the four RestServerConfig sub-objects" TRUE; #11984 (parse instead of cast) TRUE; #14796 (cloud read at 9b6abe0f2fd5, zero, structural) TRUE; #14691 (404) is this retirement (api-backend.json:2069), dropped. One wording nit, ③.
    • analytics- (14): #3891 (the degraded shim dropped the caller's identity and where) TRUE; #4001 (the strictness campaign, "data/ batch D" → "its data/ batch") TRUE; #3878 (one URL, two request bodies; the envelope dialect retired) TRUE; #10414 (MetricSchema.filters zero consumers) TRUE; #17598 ruling A 5642584462 (2026-09-12) re-affirmed 5651068700 (2026-09-13: "A stands") → "Maintainer ruling A of 2026-09-12, re-affirmed 2026-09-13, which tightened the array arm to exactly two string bounds" TRUE; #16322 (the driver half's migration table for the closed preset vocabulary) TRUE; PR #17593 (all four faces read the arm one way and refuse the rest with the ADR-0112 envelope) TRUE; #17124 (404) → .changeset/17124-daterange-array-arm-arity.md ("measured over one authored document and four rows") TRUE; #16041 ruling 5559824254 (batch Protocol review: 78% complete, P0 blockers resolved, Q1 2026 roadmap #57, 2026-09-06, option A contract first) TRUE; #4614 (the preset list, once three drifting copies, became one source; the 2026-08-03 ruling A) TRUE.
    • view- (15): #5869 / PR #6209 (scalar on in / not_in answered 500; now a named 400) → "An earlier fix closed the RUNTIME half" TRUE; #5685 ($gt / $gte / $lt / $lte widened to the strings the platform itself produces) TRUE; #5948 (its 2026-08-07 ruling, option A, both reading GetViewResponseSchema) TRUE; #6239 (404) is this removal itself (packages/client/CHANGELOG.md:2573), dropped; #6227 → "since the value was first shaped by its operator" TRUE; #19751 / #19514 own cards, dropped; objectui#9050 ruling C′ 5749197961 (2026-09-20 「同意」: the protocol is the only refusal set) TRUE, 「the differences are the protocol's to close」 kept verbatim in both entries; objectui#9853: 「9853 默认页大小改为50」 is the maintainer's reply recorded in 5824040487 (2026-09-24T23:35Z: the display default is 50, declared once in the protocol; objectui keeps reading the spec default per ruling C′ item 1 5749197629 of 2026-09-20 and never hardcodes 50) → "the maintainer's ruling of 2026-09-24 set the platform display page size to 50, declared once in the protocol" and "(an earlier ruling on the grid's page size, which the page-size ruling restated)" TRUE; view-overlay-options-bag-judged's 「其他同意」 is ruling A 5824043998 on objectui#10380 (2026-09-24T23:35Z) → "the maintainer's ruling of 2026-09-24" TRUE.
    • package- (11 + one record): #7705 (orphaned rows) / #7780 ("5 of 5 deleted, including a foreign org's", measured by protocol.deletePackage finds zero sys_metadata rows the data plane finds 3 of — uninstall leaves orphaned rows (persistence half of #7557) #7705's dev; ruled 2026-08-12) TRUE, "exactly as the orphaned-row repair left it" TRUE; (#12) → "(protocol 12)" — the sibling entry import-run-automations-declared-default-corrected already spells "protocol 12's rest-requireauth-default-flip", TRUE; #19116 ruling 5793374037 (batch Restructure documentation into protocol-first architecture with clean URLs #217, 2026-09-23, A: retire the three contract-map entries naming paths nothing mounts, 「217 同意」) TRUE; #18604 (the HttpDispatcher measurement, already in the sentence) TRUE; #18058 ruling A 5716042643 (rebind installPackage onto the serving POST /api/v1/packages) TRUE; record 5856869656 (batch 🔗 Broken links detected in documentation #227 item 3, 2026-09-27, A, 「同意」: the wrapped install form refuses an unknown top-level key by name) → "the maintainer's ruling of 2026-09-27, option A" TRUE; #12038 ruling 5434804846 (2026-08-27, 「其他接受」, sub-question 3 → A: the false rollback declaration retired first) TRUE; #11925 (the un-annotated SDK returns; its negative compile-time guard) TRUE; #3877 (response bodies never checked against the schemas that declare them) TRUE.
    • object- (13): objectui#8221 ruling 5567944420 (batch 🔗 Broken links detected in documentation #77, 2026-09-07, option B 「其他同意」: one sort spelling, the array) TRUE, its fourth item kept verbatim; #7751 ruling 5261743573 (2026-08-12, direction A: the object-* blocks enter ComponentPropsMap) TRUE; objectui#6207 (found by the declared-arm parity gate; ruled 2026-08-25 「同意」 option A, batch 4) TRUE; objectui#5090 (the grid's data declaration aligned to ViewData) TRUE; objectui#4648 (ruled 2026-08-16, B with C's deprecated-alias carve-out: staticData not published as authoring surface) TRUE; objectui#4772 (the console's index fallback editor converged onto IndexSchema, where removed) TRUE; #5114 (a console filter save answered 422: a strict schema refusing the filter-builder's id) → "the kind that had already made a console save answer 422 (a strict schema refusing a key the console itself writes)" TRUE; "批 20 held site 14 open" → the campaign held this site open, TRUE.
    • sharing- (14): #6206 (404) → assemble-execution-context.ts:17-20 (the share-link copies omitted accessible_org_ids; both surfaces converted to pass the whole envelope) and plugin-approvals/CHANGELOG.md:2968-2970 ("applying the 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find —— group 租户姿态下 Layer 0 墙恒判否 #6206 ruling — enforcement adjudicates on the whole envelope, never a per-site subset"), the date 2026-08-07 from #6430's own body ("Part of 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find —— group 租户姿态下 Layer 0 墙恒判否 #6206, maintainer 2026-08-07 ruling A") → "completing the maintainer's ruling of 2026-08-07 on the share-link context (enforcement adjudicates on the WHOLE envelope, never a per-site subset)" TRUE; #6430 / PR #6511 (404) → "the share-link twin, which that same ruling moved onto the whole context" TRUE; #6523 (404) / PR #7068 (36 signatures converged), PR #7140 (sharing + audit), PR #7206 (approvals + reports), #7070 (the split), #7218 (its deferred deletion, this card) → "One change converged the contracts, two more re-annotated the four implementations (sharing and audit, then approvals and reports), and this change removes the now-unreferenced declaration, the deletion that split had deferred" TRUE; #1878 (the metadata property liveness audit: security props parsed but never enforced) and #6350 (the stock reconciliation of the v17 train's breaking changesets, ruled 2026-08-11) TRUE.
    • audit- (14): #7675 ruling 5261744983 (maintainer 2026-08-12: two halves — build the cheap writers login / logout and config_change, retire the values with no feature; 原则记录 verbatim) TRUE, the 原则记录 kept verbatim in both entries; #8144 (writers on the auth session hooks) / #8145 (config_change from the settings service) TRUE; #8147 / #8315 own cards dropped, "(triage 2026-08-13)" is 5276103743 TRUE; #1883 (open, the undelete / purge permission lifecycle, the M2 anchor) / #3146 (open, soft delete / recycle bin) → "neither built yet", "both held open, not declined" TRUE; #8011 (the credential-storage verification re-measured two "hashed at rest" declarations; settled by making the declaration cite its mechanism) TRUE.
    • flow- (11 + surface 2 + two records): #4247 (two defaults, schema 0 / engine 3, already in the sentence) TRUE; #19961 own card dropped; hotcrm#1555 (403) → .changeset/15429-decision-edge-branching-first-match.md:18,91 ("hotcrm#1555 rendered a refusal screen AND ran the conversion in one execution"; the node lead_conversion.decision_duplicate) → "a CRM application's lead-conversion flow rendered a refusal screen AND ran the conversion in one execution" TRUE; surface: #17322 (registerFlow refuses a blank config.condition through the edge door's own schema) and #17495 (objectstack validate reports it) → "the two later changes that rebound AutomationEngine.registerFlow and objectstack validate to the edge door's own rule" TRUE; #15807 / #15430 / #15662 → "the line that first refused an ast-only envelope no engine can evaluate, and refused a non-string node predicate at registration instead of letting the evaluator answer it a silent false" TRUE; record 5550509137 (2026-09-05, an ast-only envelope driven through AutomationEngine.evaluateCondition directly answers false) → "measured on 2026-09-05 by driving an ast-only envelope through AutomationEngine.evaluateCondition directly" TRUE; #17493 ruling A 5651023407 (2026-09-13 「同意」: the two sibling predicate slots refuse a blank string at authoring; #15572's pin re-judged) → TRUE, near-verbatim; #17322 (the structural config.condition) / #15811 (every evaluated source non-blank) TRUE.
    • http- (13): #9650 / #9835 (the counter, ruled 2026-08-18 onto the transport; the IHttpServer response-observing hook its principled successor) and #9834 / #10004 (404; semconv.ts:49 and the observability CHANGELOG pair them as the histogram's move) → "the request counter, then the latency histogram, both through the response-observing hook the transport was given" TRUE and consistent with the entry's own unchanged replacement text (IHttpServer.afterResponse); #5122 / #3977 named by the two entry ids the sentence already carried; #9834 own card dropped; #4938 (the CONFIG half, ruled 2026-08-04) → "The first removed the CONFIG half" TRUE; #4834 (the dynamic plugin-loading family), #4988 (the ui/ interaction configs), #5055 (the widget / i18n shapes) → TRUE; #5295 own card dropped.
    • Carry-overs. 18.api-error-retry-after-unit-in-key: "ruled in deliberately: its 2026-09-05 population ruling puts the ~16 runtime-emitted measurements in scope … and names ApiError.retryAfter explicitly, with its own BREAKING note" is 5548763981 verbatim in substance (2026-09-05T02:32Z, batch Release version 0.1.x for ObjectStack Protocol packages #43) — the stage-5 date nit is closed. 18.inline-grid-column-currency-scale-refused: 5791803339 (batch Add metadata extension protocol for plugin extensibility #215 item 1, 2026-09-23, B: scale retired from currency) and 5805782503 (batch 🔗 Broken links detected in documentation #218 item 2, 2026-09-24, 乙: a currency's ISO 4217 minor unit decides its display) → "the maintainer's ruling of 2026-09-23 (option B) … and the ruling of 2026-09-24 (option 乙 — …)" both dates and both options TRUE; the record ids and batch numbers are gone.
    • The dropped numbers. Nine decision-batch numbers (#27, #43, #57, #77, #117, #215, #217, #218, #227 — my enumeration of the base's short tokens in the ten families, #10 and #12 apart), their item numbers, "batch D", 「批 20」, "site 14", "batch adjudication batch 4", 「五问一批」 and "C′ item 1" each give way to the ruling's date and content above; the acknowledgements 「同意」 ×2, 「其他同意」 ×2, 「217 同意」, 「其他接受」 and 「9853 默认页大小改为50」 likewise (the last carried a tracker number itself; its content, 50, is stated in words). Kept verbatim: 「the differences are the protocol's to close」 ×2, the sort ruling's fourth item, 「every other operator takes a scalar」, 「lowers to a deep-equality comparand」, 「persistViewPatch 只存 patch,不存 merged base」 and the audit ruling's 原则记录. Prime Directive #10 in package-manifest-version-grammar-enforced names AGENTS.md's rule 10 (AGENTS.md:172 ff. on main: "never advertise or demo a capability …"), kept as stages 2–5 kept #10 / #12, and the pin's TRACKER_ID is #\d{4,5}\b by design; (#12) in package-uninstall-explicit-all-tenants meant protocol 12, now spelled so.
  3. Census — reproduced with my own instrument (tokeniser over every file under entries/, string runs under the three keys, #\d{4,5}\b; surface apart; comment tokens apart; 751 files, 313 semantic entries, 0 unevaluable). Base fb386074: whole tree 461 (28/408/25), surface 5, comment lines 832; the nine families 47 entries, 122 (6/112/4) in 31 entries (rest- 6 / 17, view- 10 / 15, analytics- 6 / 14, audit- 2 / 14, sharing- 2 / 14, http- 2 / 13, object- 7 / 13, flow- 6 / 11 + 2 surface, package- 6 / 11), 90 distinct #NNNN tokens (the dev's 91 counts 8758 on objectui), short 9 in the nine families and 2 in inline-. Head: all nine families 0, surface 0, short 1 (the kept #10); inline- short 2 → 0, record ids 2 → 0; the seventeen earlier families still 0; whole tree 339 (22/296/21), surface 3, comment lines 832. Short whole-tree reads 51 → 41 on my instrument against the dev's 50 → 40: the same delta of 10, a constant one-count difference of instrument shape, not a missed site. Lit control 17.aggregation-node-distinct-retired 7 (1/6/0) both sides. Nothing the four fields carry was missed, cross-repo spellings included.
  4. Pin — widened by a necessary consequence, not weakened. COVERED_PREFIXES 17 → 27: the nine families plus inline-. The claim named nine; the dev declares the tenth. Judged: the pin's second it block asserts for (const id of REWRITTEN) expect(ids, …).toContain(id) over FAMILY = step.semantic.filter(s.id.startsWith(prefix)), so a listed id whose prefix is uncovered fails the file; the claim's own floor rule ("REWRITTEN raised from 113 by the entries changed") puts the admitted carry-over entry in the list; inline- therefore follows from the claim, and since it selects exactly one entry (inline-grid-column-currency-scale-refused, read at head) it pins nothing this PR did not rewrite — a consequence of the carry-over, not a widening. REWRITTEN 113 → 147, sorted, no duplicates; the 34 added ids are exactly the changed entries minus api-error-retry-after-unit-in-key (already listed); every listed id has a covered prefix; package- selects 6 entries and no packages- one; no covered-family entry at head carries a tracker id in its four fields. The diff's only hunks are the header comment, the one COVERED_PREFIXES line and the REWRITTEN insertions; the code outside the two arrays is token-identical, so the three it blocks and every expect are textually unchanged.
  5. Generated artifacts — exact. registry.ts parsed at base and head: 313 entries both sides, comment tokens, imports and code skeleton identical, 1,565 properties compared by value or token signature with 0 non-prose differences, exactly the 35 ids differ; all 313 head registry entries equal the head entry files on surface / replacement / reason / acceptanceCriteria. spec-changes.json: 1,234 leaf paths both sides, the same path set; 28 leaves differ and each is exactly a changed entry's field, base value → head value; the 12 protocol-17 changed entries, all projected. docs/protocol-upgrade-guide.md: 477 lines both sides, 17 removed / 17 added, every changed line contains the corresponding base / head field verbatim and every replaced pair is explained by that substitution alone; the same 12 entries. Only protocol-17 entries appear, as the generators project.
  6. Check-runs on 472ee29b (last read after the dev report, 2026-09-29): 34 runs, 28 success, 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke — the roster skips stage 5 recorded), 0 failed, 3 still running: Test Core (1/6), Test Core (5/6), Test Core (6/6); judged on the 31 completed. Green include Lint & Repo Gates (the registry / spec-changes / upgrade-guide / generated / doc-authoring / changeset gates), Check Changeset, Build Core, all four Type Check jobs, Spec property liveness, Temporal Conformance, Dogfood Verify CLI and the three Dogfood shards, Test Core (2/6) (3/6) (4/6), Governed Surface Queue Guard, and the single-writer / single-issue / Part-of / branch-claim guards. Part-of PR must not also close its card is green: the body's first line is Part of #20233 and it carries no closing keyword. The dev's local runs are superseded by these verdicts.
  7. Changeset — every sentence true. '@objectstack/spec': patch; Clause-②: no on its own line; "some of which no longer resolve" (the nine 404s), "some in another repository" (objectui#, hotcrm#), "ADR ids are kept", the two carry-overs named, "Text only: no entry id, from / to, conversion or matching logic changes", "One entry's surface … drops the two tracker numbers it carried and names nothing else differently", "the generated … carry the same text" — all verified above.

② Semver level

patch is correct: no accept set moves, no export, key or matcher changes; only the author-shown guidance text of 35 entries, their three generated projections, a widened queue-tier pin and a changeset. Clause-②: no with no arm is the well-formed declaration: no new authorable key, no accept-set narrowing or widening, so no Clause-② review is owed beyond this at-tier record. Check Changeset and Lint & Repo Gates (check:changeset-no-major, check:adr-0087-registration) are green on the head. The three commits' trailers carry no model identifier.

③ Boundary flags

Implemented-by: claude/issue-20233-migrate-meta-tracker-free-stage-6
Reviewed-by: session_01ARcDurZ5j34RdqsGgc4jgH

VERDICT: PASS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants