Repository navigation
Protocol review: 78% complete, P0 blockers resolved, Q1 2026 roadmap - #57
Closed
huangyiirene with Copilot wants to merge 3 commits into
Closed
huangyiirene with Copilot wants to merge 3 commits into
huangyiirene with Copilot wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Review completed protocols for optimization opportunities
Protocol review: 78% complete, P0 blockers resolved, Q1 2026 roadmap
Jan 21, 2026
Contributor
|
This PR is very large. Consider breaking it into smaller PRs for easier review. |
This was referenced Sep 6, 2026
os-warren
pushed a commit
that referenced
this pull request
Sep 7, 2026
…pe with registration's own refusal `evaluateCondition` derived `exprStr` with a `typeof` guard covering only the bare-string arm, so an envelope whose `source` was present and not a string became that value and `.trim()` threw a bare `TypeError` naming no flow, no node and no expression. Two sibling arms shared the same unguarded read: a value that is neither text nor envelope-shaped read as an EMPTY condition and answered a silent `false` — on the same key a start node's trigger gate is read from — and a malformed envelope under a non-predicate dialect answered `false` one statement earlier still, at the dialect check. #15662 closed this reject set at the producer; the evaluator was left disagreeing with it in a different vocabulary. Per the maintainer's ruling (decision batch #57, option A) evaluation now calls `structuralConditionRefusal` — the SAME constructor `registerFlow` calls, not a second hand-written envelope that could drift — as the method's first statement, above the dialect check so all three arms are covered. Controls pinned alongside: bare CEL text and both envelope spellings still evaluate; an `ast`-only envelope still answers `false` (that population is #15430/#15807's); a well-formed `cron` envelope still answers `false` rather than being refused; absent/`null`/empty/whitespace conditions are still "not authored"; and a malformed STRING still earns the brace trap or the §1c CEL fault, never the shape refusal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
This was referenced Sep 7, 2026
huangyiirene
pushed a commit
that referenced
this pull request
Sep 7, 2026
…osed dateRange contract no longer admits Not a test disabled to get green. #16041 closed the string arm of timeDimensions[].dateRange to the date-range-presets.ts vocabulary (maintainer ruling, decision batch #57), and this retirement is the maintainer's option-B decision of 2026-09-07, chosen over routing the fixtures around the schema door because that would have kept a live pin on the silent-widening fallback #16041 exists to abolish. The three memory-analytics-date-range-{dst,timezone,utc-window} files fed the retired relative dialect ('last 3 days', 'last 7 days', 'last 1 week', 'last 2 weeks', 'last 1 month', 'last 3 months', 'last 1 year') and one garbage string through asQuery = AnalyticsQuerySchema.parse, so on this branch they read 15 failed | 37 passed (52) plus three TS2322, on input production can no longer deliver through any door. Re-spelling was measured, not assumed: driving the built dist directly, only 'today' produces a window; every other preset (last_7_days, last_week, ...) falls to parseDateRangeString's [range, range] fallback and matches every row, because the parser keys on startsWith('last '). So 0 of the 15 cases are expressible until #16322 aligns the parser. Form: it.todo per retired case, original title kept and suffixed with the reason; a site comment at each naming #16041 and #16322 and stating the coverage lost; the two surviving helpers' `range` parameter retyped from string to AnalyticsDateRange (the closed contract), which is what clears the TS2322. No surviving assertion changed. The dst file's driver harness (CUBE / asQuery / probesSelected / probesFor) had no surviving caller and is removed; its cell table and all eight controls survive. COVERAGE LOST until #16322 reinstates it in preset form: - dst: all 13 driver cells, i.e. the ENTIRE `last N UNIT` arithmetic-leg DST coverage in driver-memory goes to zero: spring-forward and fall-back, the day / week / month / year legs, both hemispheres, the two non-whole-hour zones (St_Johns -03:30, Chatham +12:45). - timezone: the one `last N` case anchoring on the SUPPLIED zone's calendar day and midnight (Asia/Shanghai, 'last 7 days'). - utc-window: the fallback fence on 'not a range at all'; its zone-independence was a property of an answer that matched every row, and #16322 owes the driver-side refusal pin in its place. What survives: the 'today' leg's DST and zone coverage, i.e. the 7 timezone cells including the 23-hour America/New_York spring-forward day and the 11 utc-window cells, plus every control on the dst cell table. Reinstatement note for #16322: last_7_days / last_30_days / last_90_days are rolling day-leg windows; last_week / last_month / last_quarter / last_year are calendar windows, not n units back, so the week / month / year cells need re-measured transition instants under preset semantics. Measured: driver-memory typecheck exit 2 (three TS2322) before, exit 0 after; the three files 15 failed | 37 passed before, 37 passed | 15 todo after, also under TZ=America/New_York; full package 1095 passed | 15 todo (1110); spec and runtime pins unmoved (235/235, 37/37); dist byte-identical under a forced rebuild, so the 16 dependents cannot observe a test-only diff. The same 15 failures are what reddened Temporal Conformance on d8a3fd2 (its non-SQL leg runs driver-memory under TZ=America/New_York); the InnoDB line in that job's tail is the MySQL container's echo of a passing negative test and appears in main's green run too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 9, 2026
…pe with registration's own refusal (objectstack-ai#16438) `evaluateCondition` derived `exprStr` with a `typeof` guard covering only the bare-string arm, so an envelope whose `source` was present and not a string became that value and `.trim()` threw a bare `TypeError` naming no flow, no node and no expression. Two sibling arms shared the same unguarded read: a value that is neither text nor envelope-shaped read as an EMPTY condition and answered a silent `false` — on the same key a start node's trigger gate is read from — and a malformed envelope under a non-predicate dialect answered `false` one statement earlier still, at the dialect check. objectstack-ai#15662 closed this reject set at the producer; the evaluator was left disagreeing with it in a different vocabulary. Per the maintainer's ruling (decision batch objectstack-ai#57, option A) evaluation now calls `structuralConditionRefusal` — the SAME constructor `registerFlow` calls, not a second hand-written envelope that could drift — as the method's first statement, above the dialect check so all three arms are covered. Controls pinned alongside: bare CEL text and both envelope spellings still evaluate; an `ast`-only envelope still answers `false` (that population is objectstack-ai#15430/objectstack-ai#15807's); a well-formed `cron` envelope still answers `false` rather than being refused; absent/`null`/empty/whitespace conditions are still "not authored"; and a malformed STRING still earns the brace trap or the §1c CEL fault, never the shape refusal. Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 9, 2026
…e-range preset vocabulary (objectstack-ai#16041) (objectstack-ai#16618) * feat(spec): close timeDimensions[].dateRange's string arm to the date-range preset vocabulary (wip) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * feat(spec): changeset, ADR-0087 registration and regenerated projections for the closed dateRange vocabulary (wip 2) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * chore(spec): regenerate api-surface, export-origins, declaration-map and reference docs for AnalyticsDateRangePreset (wip 3) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * test(spec): pin the two isomorphic dateRange aliases (ADR-0122) and compile the schema example (wip 4) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * test(service-analytics): re-spell the single-day dateRange fixture in the array form The closed string vocabulary for timeDimensions[].dateRange retires the bare-date spelling this fixture authored, so the package's required TypeScript Type Check went red on one line (TS2322 at line 187). The fixture now writes the same single-day window as ['2026-01-20', '2026-01-20']; the strategy lowers both spellings to the identical $gte/$lte bounds, so the expected values are untouched. The test's title still names the retired dialect on purpose: a comment above it records that retiring the test belongs to the driver-alignment card, together with the strategy's degeneration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * chore(spec): regenerate content/docs/references/index.mdx on the merged tree Regeneration commit for the forward merge of origin/main (554a160) into this branch, kept apart from the merge commit so the two can be read separately. `gen:schema` + `gen:docs` on the merged tree changed exactly one file: the references index, whose counts are now the union of both sides — main's ResumeFailureDetails (API 436 -> 437) plus this branch's AnalyticsDateRange / AnalyticsDateRangePreset (Data 166 -> 168), total 1575 -> 1577. No other generated artifact moved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno * test(driver-memory): retire the 15 date-range pins whose input the closed dateRange contract no longer admits Not a test disabled to get green. objectstack-ai#16041 closed the string arm of timeDimensions[].dateRange to the date-range-presets.ts vocabulary (maintainer ruling, decision batch objectstack-ai#57), and this retirement is the maintainer's option-B decision of 2026-09-07, chosen over routing the fixtures around the schema door because that would have kept a live pin on the silent-widening fallback objectstack-ai#16041 exists to abolish. The three memory-analytics-date-range-{dst,timezone,utc-window} files fed the retired relative dialect ('last 3 days', 'last 7 days', 'last 1 week', 'last 2 weeks', 'last 1 month', 'last 3 months', 'last 1 year') and one garbage string through asQuery = AnalyticsQuerySchema.parse, so on this branch they read 15 failed | 37 passed (52) plus three TS2322, on input production can no longer deliver through any door. Re-spelling was measured, not assumed: driving the built dist directly, only 'today' produces a window; every other preset (last_7_days, last_week, ...) falls to parseDateRangeString's [range, range] fallback and matches every row, because the parser keys on startsWith('last '). So 0 of the 15 cases are expressible until objectstack-ai#16322 aligns the parser. Form: it.todo per retired case, original title kept and suffixed with the reason; a site comment at each naming objectstack-ai#16041 and objectstack-ai#16322 and stating the coverage lost; the two surviving helpers' `range` parameter retyped from string to AnalyticsDateRange (the closed contract), which is what clears the TS2322. No surviving assertion changed. The dst file's driver harness (CUBE / asQuery / probesSelected / probesFor) had no surviving caller and is removed; its cell table and all eight controls survive. COVERAGE LOST until objectstack-ai#16322 reinstates it in preset form: - dst: all 13 driver cells, i.e. the ENTIRE `last N UNIT` arithmetic-leg DST coverage in driver-memory goes to zero: spring-forward and fall-back, the day / week / month / year legs, both hemispheres, the two non-whole-hour zones (St_Johns -03:30, Chatham +12:45). - timezone: the one `last N` case anchoring on the SUPPLIED zone's calendar day and midnight (Asia/Shanghai, 'last 7 days'). - utc-window: the fallback fence on 'not a range at all'; its zone-independence was a property of an answer that matched every row, and objectstack-ai#16322 owes the driver-side refusal pin in its place. What survives: the 'today' leg's DST and zone coverage, i.e. the 7 timezone cells including the 23-hour America/New_York spring-forward day and the 11 utc-window cells, plus every control on the dst cell table. Reinstatement note for objectstack-ai#16322: last_7_days / last_30_days / last_90_days are rolling day-leg windows; last_week / last_month / last_quarter / last_year are calendar windows, not n units back, so the week / month / year cells need re-measured transition instants under preset semantics. Measured: driver-memory typecheck exit 2 (three TS2322) before, exit 0 after; the three files 15 failed | 37 passed before, 37 passed | 15 todo after, also under TZ=America/New_York; full package 1095 passed | 15 todo (1110); spec and runtime pins unmoved (235/235, 37/37); dist byte-identical under a forced rebuild, so the 16 dependents cannot observe a test-only diff. The same 15 failures are what reddened Temporal Conformance on d8a3fd2 (its non-SQL leg runs driver-memory under TZ=America/New_York); the InnoDB line in that job's tail is the MySQL container's echo of a passing negative test and appears in main's green run too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno --------- Co-authored-by: Claude <noreply@anthropic.com>
veigajoao
pushed a commit
to veigajoao/objectstack
that referenced
this pull request
Sep 29, 2026
…-*, package-*, object-*, sharing-*, audit-*, flow-* and http-* migration entries states each lesson in words, not tracker numbers (stage 6) (objectstack-ai#20536) Part of objectstack-ai#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 objectstack-ai#10` in `18.package-manifest-version-grammar-enforced` (a rule in AGENTS.md, as stages 2–5 kept `objectstack-ai#10` / `objectstack-ai#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" | | `objectstack-ai#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 (`objectstack-ai#27`, `objectstack-ai#43`, `objectstack-ai#57`, `objectstack-ai#77`, `objectstack-ai#117`, `objectstack-ai#215`, `objectstack-ai#217`, `objectstack-ai#218`, `objectstack-ai#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, objectstack-ai#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 'objectstack-ai#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](https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
veigajoao
pushed a commit
to veigajoao/objectstack
that referenced
this pull request
Sep 29, 2026
…data/analytics.zod.ts to the commits that decided them (stage 7) (objectstack-ai#20616) Part of objectstack-ai#20234 Clause-②: no Stage 7 of the staged sweep: `packages/spec/src/stack.zod.ts` and `packages/spec/src/data/analytics.zod.ts`, both freed by landings (PR objectstack-ai#20579 and PR objectstack-ai#20458). Its claim is `5885635758`. Every comment or docblock line in those two files that cited a tracker number answering 404 now cites the commit on `main` that decided its rule, in ruling C+D's form C, and says in its own words what was decided. Comments only: 12 lines out, 12 in, across 2 files. No code token, string literal or `describe()` text moves. No dead site stays: none of the 12 is read by literal. The census is the gate's own `node scripts/check-issue-citations.mjs --census --json`, filtered to the two paths. Before: base `0f6dcac5e9`, board enumerated (185 pages, frontier objectstack-ai#20611). After: head `cc0580d404`, board enumerated (185 pages, frontier objectstack-ai#20615). ## Measurement | file (under `packages/spec/src/`) | dead before | after | numbers, then anchor | |---|---:|---:|---| | `stack.zod.ts` | 9 | 0 | objectstack-ai#10485 ×2 (`:415`, `:1023`) to `35ad101bc`; objectstack-ai#6238 (`:633`) to `c8d6f6e08`; objectstack-ai#14192 (`:1233`) to `4d0d9445a`; objectstack-ai#14686 ×2 (`:3037`, `:3194`) to `279431e7a`; objectstack-ai#14662 ×3 (`:4510`, `:5070`, `:5293`) to `35dffeace` | | `data/analytics.zod.ts` | 3 | 0 | objectstack-ai#10194 ×3 (`:404`, `:407`, `:485`) to `2306a765c` | | **2 files** | **12** | **0** | 6 numbers removed, 6 distinct shas | Per-file counts at base equal the claim's (9 and 3, from stage 6's census). A second instrument agrees site for site: every `#N` in the two files, classified by the TypeScript parser, and each of the 84 distinct numbers of 100 or more probed by REST `issues/N` without following redirects (the other 3 are the ordinals `Prime Directive objectstack-ai#12`, `batch objectstack-ai#23`, `batch objectstack-ai#57`). - Base: 244 sites, all in comments (0 strings, 0 code). 78 numbers answer 200 and 6 answer 404: the same 6 numbers and the same 12 sites as the gate. - Its string-class positive control found 11 string sites in `kernel/manifest-unknown-keys.test.ts` and `packages/cli/src/utils/lower-callables.test.ts`. - Head: 232 sites, 78 numbers, all 78 answer 200 (the same 78), none answers 404. - Lit controls objectstack-ai#16862, objectstack-ai#16847 and objectstack-ai#17698 answered 200 at every checkpoint (3 at base, 3 at head); dead controls objectstack-ai#16714, objectstack-ai#16715 and objectstack-ai#16697 answered 404 at every checkpoint. ## Why each anchor decides its line Each sha resolves uniquely, is an ancestor of `origin/main` (and of the base), and has one parent. No file under `docs/adr/**`, `docs/NORTH-STAR.md` or `scripts/adr-anchors/` names any of the six numbers or records these rules, so each takes the commit rung, as stages 1–6 did. - **objectstack-ai#10485 to `35ad101bc`** (`:415`, `:1023`): retires the `themes` carrier key and `ThemeSchema` under ADR-0049. Its message records the ruling, "Ruled B (退役授权面, 2026-08-21)", and its own `stack.zod.ts` diff wrote both lines. `:415` keeps ADR-0049 and the ruling in its words; the D3 entry `stack-themes-carrier-retired` it names on `:423` is unchanged. This is the anchor stages 1, 5 and 6 used for the same retirement. - **objectstack-ai#6238 to `c8d6f6e08`** (`:633`): widens the array member of `functions` so its `handler` also takes the lowered string ref, which is the fix for `objectstack build` refusing its own array output. Its message names objectstack-ai#6238, and its own diff wrote the line. objectstack-ai#4343 and objectstack-ai#4976 on the same line stay (both 200). - **objectstack-ai#14192 to `4d0d9445a`** (`:1233`): turns `ManifestSchema` and its nested blocks into `strictObject` and flips the assembled-body strip pin to a refusal pin; each of its sub-commits names objectstack-ai#14192. The line itself was written later by `c78c9180de`, whose own message says "objectstack-ai#14192 closed ManifestSchema with strictObject", so the commit that closed it is the anchor. - **objectstack-ai#14686 to `279431e7a`** (`:3037`, `:3194`): "defineStack refuses two actions that resolve to one scope-qualified runtime key". Its subject names objectstack-ai#14686, and its diff adds `collectDuplicateActionKeyErrors` and the changeset for that refusal. Both lines were written later by `773a99960a` (PR objectstack-ai#15022), whose message describes the same "same-key rule, which runs before the merge". - **objectstack-ai#14662 to `35dffeace`** (`:4510`, `:5070`, `:5293`): "composeStacks refuses two stacks whose actions resolve to one scope-qualified runtime key". It checks the composed set with the rule `defineStack` applies within one stack, with no `actionConflict` option (maintainer ruling 2026-09-03). Its message does not name objectstack-ai#14662; its own `stack.zod.ts` diff wrote all three `(objectstack-ai#14662)` lines. - **objectstack-ai#10194 to `2306a765c`** (`analytics.zod.ts:404`, `:407`, `:485`): binds `analytics_cube` (and `theme`) in `UNREGISTERED_KIND_SCHEMAS`, so `PUT /meta/analytics_cube/:name` parses through `CubeSchema`, and gives `CubeSchema` the `...MetadataProtectionFields` spread. Its message names objectstack-ai#10194, and its own diff wrote all three lines. The `[objectstack-ai#10194]` markers become `[commit 2306a76]`, the spelling stages 1 and 5 already use in `kernel/metadata-type-schemas.ts`. ## Mechanical proof - **Token guard** (my `tokcmp.mjs`: TypeScript 6.0.3 leaf tokens, JSDoc kinds excluded, controls mutate the head text in memory only). Base `0f6dcac5e9` against the head, 2 files, 17,249 base tokens: - Real run: 0 files with a token change (exit 0). - Comment-insertion control (`data/analytics.zod.ts`): 0 (exit 0). - Code-insertion positive control (`stack.zod.ts`, a declaration appended): DIFFER at token 15388 (exit 1). - String positive control (the first `StringLiteral` the parser locates in each file): DIFFER at token 5 (exit 1), once per file. - `describe()` positive control (the first `.describe()` string argument the parser locates: `stack.zod.ts:133`, `analytics.zod.ts:244`): DIFFER at tokens 507 and 442 (exit 1). - **Line balance**: `stack.zod.ts` +9/−9, `data/analytics.zod.ts` +3/−3; line counts equal at base and head (5344 and 853). - **Tracker numbers**: added-not-removed is empty in both files, and no `PR #N` is on an added line. Net-removed: 12 sites, 6 numbers. The only numbers on added lines are objectstack-ai#4343 and objectstack-ai#4976, which stay on `:633`. - **Shas**: 6 distinct on added lines, 0 on removed lines. - `rev-parse --disambiguate` answers 1 object for each. - `merge-base --is-ancestor` exits 0 for each, against `origin/main` `7510663c87` and against the base; each is single-parent; the repository is not shallow. - **Literal readers**: all 26 string, template and regex literals in the repository that carry one of the six numbers (42 code files) were matched against the two files' base text: 0 occur there. Each removed line was also cut into 4-word windows (96) and searched across the tree: the 9 hits inside string literals are other files' own test titles sharing a phrase ("the ADR-0010 protection envelope", "an assembled body is"), and none reads either file. The source-text readers of the two files read code, not these comments: `compose-stacks-refusal-envelopes.test.ts` counts `throw new Error(`, and `check-stack-collection-maps.mjs` and `check-skill-top-level-keys.mjs` read the declared collections and keys. ## Tests and gates (at head `cc0580d404`) - `pnpm exec turbo run build --concurrency=2 --filter=./packages/* --filter=./packages/*/*` under `os-verify-lock`: Tasks 71 successful, 71 total, VERDICT command-exit 0. - `pnpm --filter @objectstack/spec check:generated` under the lock: all 15 generated artifacts up to date, `check:docs` over `content/docs/references/**` included; VERDICT command-exit 0. No reference page projects any of the 12 lines, so none is regenerated. - `vitest run --maxWorkers=2` under the lock over the two files' own suites (`src/stack*`, `src/compose-stacks*`, `src/define-stack*`, `src/assembled-package-body`, `src/data/analytics*`, `src/data/cube*`): Test Files 35 passed (35), Tests 976 passed (976). - The 37 spec suites that read source text across `src/`, or carry one of these numbers, under the lock: Test Files 37 passed (37), Tests 759 passed (759). - `scripts/{category-title,dist-freshness,dist-freshness-adoption,file-description,strictness-ledger,strictness-ledger-doc,root-index,skill-map-guards,export-origins,split-entries,root-entry-type-nameability.pin}`, `scripts/liveness/{evidence,tombstoned-row-status}`; - `src/type-alias-convention.pin`, `src/eager-entry-import`, `src/api/{api-entry-graph.pin,auth,export-job-family-retirement}`, `src/ai/tool-confirmation-prescription-tense.pin`, `src/data/{currency-mode-family-closure.pin,external-lookup-retirement}`, `src/identity/position-delegatable-enforcer.pin`, `src/integration/{connector-connection-timeout-retirement,connector-resilience-keys-retirement}`, `src/security/rls-tags-retirement`, `src/shared/{alias-integrity,retired-key-migrate-sentence}`, `src/system/{compliance-families-retirement,constants/platform-object-names,email-template-floor-locale-parity.pin,message-queue-retirement}`, `src/ui/{action-requires-confirmation-docblock.pin,i18n,interaction-config-retirement,strictness-batch14}`, `src/kernel/{manifest-unknown-keys,metadata-type-schemas}`. - Left to CI: `scripts/{build-schemas-check-mode,def-key-collisions,openapi-self-consistency}` (each rebuilds artifacts in a temp tree) and `scripts/{check-generated-ledger,check-generated-fix-rebuild.pin}` (read the ledger and `dist`). None reads comment text. - `pnpm --filter @objectstack/spec typecheck` under the lock: exit 0; `check:test-typecheck` OK (53 files / 251 errors / 138 pinned signatures held). - Lint, a proven narrowing: `eslint --no-inline-config --format json` over the 2 files gives 2 files, 0 errors, 0 warnings. - `isPathIgnored` is false for both, read through eslint's API. - `eslint.config.mjs:327-328` says type-aware linting is never enabled, so a comment edit cannot move an untouched file's verdict. - The repo-wide `pnpm lint` is CI's. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands`: 79 families derived and run, every one exit 0. `--ran` reads "79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN". Among them: - `pnpm check:issue-citations` (self-test, 114 cases in 8 batteries) and the live diff-scoped `node scripts/check-issue-citations.mjs`: it judged the 2 citations on added lines, objectstack-ai#4343 and objectstack-ai#4976, and both are live issues. - `pnpm check:doc-authoring`: 16,804 customer-facing strings across 1,179 spec sources clean; the sibling baseline holds. - `pnpm check:stack-collection-maps`: 8 enumerations reconciled against 31 declared collections. - Changeset: `patch` for `@objectstack/spec`. Both files are `src/**/*.zod.ts`, which `files[]` ships verbatim, and the rewritten docblocks reach `dist`: "posture: commit 4d0d944 closed" and "[commit 2306a76] This docblock used to say" are each in 2 `.d.ts`, their old spellings in 0. Positive control: the unchanged neighbouring sentence "BY INHERITANCE — an undeclared key on one is REFUSED" is in the same 2 `.d.ts`. - Merge probe: a no-driver `merge-tree` of the head onto `origin/main` `7510663c87`, from a bare shared clone, exits 0. The 3 commits `main` gained since the base touch neither file nor the citation or derivation scripts, and a re-derivation prints the same 79 commands. No merge was made. - No ablation or reverse verification: the change is comment-only, so there is no behaviour to invert. ## Hypotheses (measured first) 1. **Holds.** 12 dead sites at the tip, 9 in `stack.zod.ts` and 3 in `data/analytics.zod.ts`, equal per file to stage 6's census. 2. **Holds.** Read at 2026-09-29T07:36Z and again at 08:16Z, after the last push and before this PR was opened: all open PRs' full file lists (9 PRs, 166 files at the second read) and the newest `Claim:` on all 11 `pm:dispatched` cards. None names either file, except this card's own claim. 3. **Holds, with nothing to keep.** All 12 sites are comments. No test string, exported string or `describe()` text carries one, and no test or script reads any of them by literal. 4. **Holds.** No generated reference page projects these lines; `check:docs` is green with no regeneration. ## Deviations - None to the file surface: the 12 claimed lines and one changeset, no generated page needed. - Commit trailers follow AGENTS.md's model-free pair (`Claude-Session` plus `Co-authored-by: Claude`); the pre-push trailer check passed on every push. ## Acceptance notes **What stays for later stages.** The gate's census at this PR's head (base `0f6dcac5e9` plus this PR) reads **248** dead sites (29 numbers) in `packages/spec/src`. The only `packages/spec/src` change `main` has made since the base (objectstack-ai#20610's migrations entry and registry) adds four live numbers and removes none, so 248 also stands at the tip `7510663c87` plus this PR: - `migrations/` **233**: objectstack-ai#20233 edits the same entry files (PR objectstack-ai#20607 holds `migrations/registry.ts`). - `conversions/registry.ts` **12**: PRs objectstack-ai#20570 and objectstack-ai#20587 hold it. - `integration/connector.zod.ts` **1**: PR objectstack-ai#20587 (objectstack-ai#20287). - `data/api-derivation.ts:163` (objectstack-ai#6259) and `identity/identity.zod.ts:230` (objectstack-ai#8715), **1** each: kept because tests read them by literal, so removing them is form D. **Outside the gate's census: test files.** The gate defers `*.test.ts`. The same six dead numbers still stand at 15 comment sites and 10 test-title strings in `packages/spec/src` test files: - `data/analytics-strictness-batchd.test.ts:96` (comment, objectstack-ai#10194) and its title `:93`. This file is in the `analytics*` set stages 3 and 4 excluded while PR objectstack-ai#20458 held it; `analytics-date-range-two-bound-window.test.ts` and `cube-member-inner-name-retirement.test.ts` were in that set too and are not re-measured here. - The package root: `compose-stacks-action-echo.test.ts:20`, `:34`, `:200` (objectstack-ai#14686) and titles `:176`, `:224`; `compose-stacks-action-key-collision.test.ts:3` (objectstack-ai#14662); `stack-top-level-strict.test.ts:103` (objectstack-ai#10485) and title `:128`; `type-alias-convention.pin.test.ts:257`, `:1572`, `:1937` (objectstack-ai#10485). - `shared/`: `metadata-collection.test.ts:250`, `metadata-url-spelling.test.ts:51`, `:72`, `:168` (objectstack-ai#10485), `:257` (objectstack-ai#10194), title `:254`. `automation/sync-retirement.test.ts:207` (objectstack-ai#10485). - `kernel/`: `manifest-unknown-keys.test.ts`, four titles (objectstack-ai#14192); `metadata-type-schemas.test.ts:422`, a title (objectstack-ai#10194). - Stage 6 took the package root, `shared/` and `automation/` through the gate's census, which never lists a test file, so test-file comment lines there may carry other dead numbers as well. That wider population is not measured here. **Outside `packages/spec/src`.** The same six numbers stand at 44 more sites (`packages/{metadata-protocol,objectql,rest,runtime,cli,core,metadata,qa}`, `examples/`, `scripts/`, `packages/spec/scripts/`), and at 19 sites in `migrations/` (the objectstack-ai#20233 area). **Rung.** The objectstack-ai#10485 retirement also has the ADR-0087 D3 entry `stack-themes-carrier-retired`, which `:423` already names. This PR takes the commit rung, as stages 1–6 did. **Wording, each true of its commit.** `:3037` and `:3194` now read "commit 279431e's same-key refusal": the refusal that commit added, in lines `773a99960a` wrote. `:1233` reads "commit 4d0d944 closed `ManifestSchema`", in a line `c78c9180de` wrote. --- _Generated by [Claude Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 2, 2026
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Comprehensive review of ObjectStack protocol specifications to assess completion status, identify gaps, and establish execution roadmap.
Current State
Completion: 78% (35/46 protocols)
Critical Achievement: All 4 P0 blockers resolved (Widget Contract, Plugin Lifecycle, Driver Interface, Trigger Context). Plugin ecosystem, custom UI extensions, and multi-database support now unblocked.
Gap Analysis
High Priority Missing (7 protocols):
marketplace.zod.ts- App store metadata (2-3d)tenant.zod.ts- Multi-tenancy isolation (3-5d)events.zod.ts- Event bus protocol (2-3d)realtime.zod.ts- WebSocket sync (3-4d)model.zod.ts- AI model registry (3-4d)rag.zod.ts- RAG pipeline (4-5d)nlq.zod.ts- Natural language query (5-7d)Optimization Needed:
Deliverables
PROTOCOL_REVIEW_SUMMARY.md (9KB)
PROTOCOL_REVIEW_REPORT.md (18KB)
NEXT_STEPS_ACTION_PLAN.md (18KB)
Q1 2026 Execution Plan
Sprint 1-2 (Weeks 1-4): Query & Validation Enhancement
Sprint 3-4 (Weeks 5-8): Test Coverage & Platform
Sprint 5-6 (Weeks 9-12): Real-time & Events
Sprint 7-8 (Weeks 13-16): Consolidation
Naming Convention Audit
✅ All protocols follow conventions:
camelCase(e.g.,maxLength,referenceFilters)snake_case(e.g.,name: 'first_name')Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.