Skip to content

fix(spec): connector preserves the ADR-0010 protection envelope instead of silently stripping it (#6362) - #6900

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6362-connector-protection-envelope
Aug 9, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-6362-connector-protection-envelope

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #6362

Premise — re-verified at origin/main, and it held

ConnectorSchema is still a non-strict z.object with no ADR-0010 protection
envelope. Measured before any edit, by round-tripping a loader-stamped catalog
descriptor through the schema the metadata registry actually resolves for
connector:

connector:    kept=[] lost=[_lock,_lockReason,_lockSource,_provenance,_packageId,_packageVersion,_lockDocsUrl]  => DROPPED (all)
webhook:      kept=[all 7] lost=[]                                                                              => PRESERVED
sharing_rule: kept=[all 7] lost=[]                                                                              => PRESERVED

All seven keys gone, success: true, no error anywhere. Tolerate is not
preserve.

Why this one outlived its two siblings

Both metadata load paths call applyProtection on every type, so a
package-loaded connector carries the envelope by the time anything re-parses
it — and since #6245 bound DeclarativeConnectorEntrySchema to
PUT /api/v1/meta/connector/:name, something re-parses it on every write.

The pair splits by posture, and the quiet half is the one that survived:

posture undeclared envelope is… visibility
sharing_rule .strict() rejected — hard 422 loud; fixed in #6245
connector plain z.object accepted, then stripped silent; this PR

Every downstream reader of extractProtection / resolveLockState therefore
saw an unlocked, unattributed, org-provenance connector where the loader had
stamped a locked, package-owned one.

The fix

One ...MetadataProtectionFields spread on ConnectorSchema — the shape
#6245's dev verified on sharing_rule. Pure-additive and internal: every key
is _-prefixed and optional, no author-facing field changes, and nothing that
parsed before stops parsing. ConnectorSchema stays non-strict (subtypes
.extend() it), so the spread adds seven named keys, not a passthrough —
an undeclared underscore key is still stripped, and that is pinned.

MANDATORY: the webhook measurement — PRESERVED, no drop, no spread applied

The card asked whether webhook had the same defect and to apply the same
spread only if it did. It does not, so nothing was applied there.

Probe — the same round-trip used for connector above, driven through
getMetadataTypeSchema('webhook') (the /meta write door #6245 bound) with a
fully populated seven-key envelope, asserting the parse output key by key:
all seven survive. Reading confirms it: WebhookSchema has carried
...MetadataProtectionFields since #4001 batch 11, and the generated
integration/WebhookConfig:_packageId baseline entry already recorded it.

That reading is now a pin, not a note in a closed report
(webhook.test.ts, [#6362] PRESERVES all seven envelope keys — measured, not assumed), so it cannot regress unobserved. The pre-existing #4001 test asserted
only two keys and only that the envelope was accepted — enough for "accepts",
not for "preserves", and an accepts-shaped assertion is exactly what was green
on connector throughout.

Reverse verification — direction predicted first, then measured

Prediction: removing the spread turns the new preservation pins red while
every pre-existing connector assertion stays green. That asymmetry is
the defect's signature — the unfixed schema parses the stamped body perfectly
well, so only an assertion over the parse output can see it.

Measured (spread removed via git checkout origin/main -- connector.zod.ts,
restored from the commit afterwards):

 × ConnectorSchema PRESERVES every stamped envelope key through a parse
 × the /meta write door (DeclarativeConnectorEntrySchema) preserves it too
 × the schema the metadata registry resolves for `connector` preserves it
 × a provider-bound instance keeps the envelope alongside the §3/§5 rules
 × declaring the envelope did not open the schema to arbitrary `_` keys

AssertionError: expected { _lock: undefined, …(6) } to deeply equal { _lock: 'no-overlay', …(6) }
AssertionError: expected [] to deeply equal [ '_lock', '_lockDocsUrl', …(5) ]

 Test Files  1 failed | 2 passed (3)
      Tests  5 failed | 186 passed (191)

5 red, 186 green — including all pre-existing connector tests and both
webhook envelope tests. Exactly the predicted direction.

Tests

New describe('ADR-0010 protection envelope (#6362)') in
connector.test.ts, driving the round-trip at all three levels, because the
base schema carrying the spread is only half an answer if the bound door drops
it:

No new test files, so the type-check coverage ledger is untouched.

Generated baselines

packages/spec/authorable-surface/integration.json gains the seven
integration/Connector:_* keys, regenerated by the spec build — matching what
#6245 recorded for security/SharingRule and security/CriteriaSharingRule.
authorable-surface.base.json was not rewritten.


Generated by Claude Code

`ConnectorSchema` tolerated the ADR-0010 protection envelope but never
declared it, so every package-load round-trip through the schema dropped all
seven `_`-prefixed keys with no error anywhere. Tolerate is not preserve.

Both metadata load paths call `applyProtection` on every type, and since #6245
bound `DeclarativeConnectorEntrySchema` to `PUT /meta/connector/:name`,
something re-parses that stamped body on every write.

This is the quiet half of the pair #6245 fixed. `sharing_rule` is `.strict()`,
so its undeclared envelope was REJECTED — a hard 422, loud, fixed there.
`ConnectorSchema` is a plain `z.object`, so it ACCEPTED the envelope, answered
success, and stripped it — leaving every reader of `extractProtection` /
`resolveLockState` looking at an unlocked, unattributed, org-provenance item.

Fix is the single `...MetadataProtectionFields` spread #6245's dev verified on
`sharing_rule`. Pure-additive and internal; the schema stays non-strict, so an
undeclared `_` key is still stripped.

`webhook` was measured in the same pass and needs no change — it has carried
the spread since #4001 batch 11 and all seven keys already survive. That
reading is now pinned rather than left as a note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
@vercel

vercel Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 9, 2026 4:02am

Request Review

@github-actions github-actions Bot added the size/m label Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

113 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/permissions/system-context.mdx (via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 9, 2026
…ope keys (#6362)

`content/docs/references/integration/connector.mdx` is GENERATED from the spec
schemas. The `...MetadataProtectionFields` spread adds seven optional keys to
`ConnectorSchema`, so the reference page's property tables go with it.

Regenerated with `pnpm --filter @objectstack/spec gen:schema && ... gen:docs`,
never hand-edited. Caught by the `check:docs` gate in the TypeScript Type Check
job.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011sGk4SKHqGRgmmqUok1P8M
@os-zhuang
os-zhuang marked this pull request as ready for review August 9, 2026 04:29
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit b5404f4 Aug 9, 2026
27 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6362-connector-protection-envelope branch August 9, 2026 04:49
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…AS (objectstack-ai#6931) (objectstack-ai#7116)

`metadata-type-schemas.test.ts` holds the invariant that every metadata type
either declares `...MetadataProtectionFields` or sits on an explicit debt list,
and that debt list is empty with a comment calling it the end state — so the
gate read as total coverage. It was not. The walk iterates
`listMetadataTypeSchemaTypes()`, which deliberately excludes the three non-KIND
stack collections bound in `UNREGISTERED_KIND_SCHEMAS` (webhook / connector /
sharing_rule). Those three are real parse doors — objectstack-ai#6245 wired them to
`PUT /api/v1/meta/:type/:name` — so the one automated check for "declares no
envelope" never ran over any of them, and all three were judged one at a time by
hand: sharing_rule surfaced as a hard 422, connector only after a silent
seven-key strip and a separate card a day later (objectstack-ai#6362 / PR objectstack-ai#6900), and webhook
was fine by accident of objectstack-ai#4001 batch 11 with nothing verifying it.

A second `it.each` asserts the envelope property — and only that property — over
`listUnregisteredKindSchemaTypes()`, sharing the same `objectShapes` walker and
`rejectedEnvelopeKeys` probe as the registered walk so the two iterations cannot
drift into judging the property differently. All three pass today, so this closes
no live bug; the value is prospective, for a fourth entry.

Reverse-verified in both directions, predicted before measured. Removing the
spread from ConnectorSchema turns the new `connector DECLARES` case red while
every case of the two original suites stays green — the blind spot, exhibited.
Adding a fourth entry with no envelope turns its `DECLARES` case red while the
objectstack-ai#4001 campaign count is unmoved.

Scope fence, per the triage ruling on objectstack-ai#6931: this enrolls the three in the test's
iteration only. `listUnregisteredKindSchemaTypes()` returns names and grants
nothing — no MetadataTypeSchema membership, no DEFAULT_METADATA_TYPE_REGISTRY
entry, no create seed, no authorization verdict, no place in the campaign count.
`listMetadataTypeSchemaTypes()` output is byte-identical, and a pinned case keeps
it that way, so objectstack-ai#2657's B/C decision stays open and unprejudged.

Fixes objectstack-ai#6931


Claude-Session: https://claude.ai/code/session_01JJpiZS4AgkrDYwZ2Amh5mw

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…acts/ to the commits and ADRs that decided them (stage 1) (objectstack-ai#20326)

Part of objectstack-ai#20234
Clause-②: no

## What changed

This is stage 1 of the staged sweep, covering
`packages/spec/src/kernel/**` and `packages/spec/src/contracts/**` and
nothing else. Later stages cover the other areas, so this PR carries
`Part of`.

Every comment or docblock site in these two areas that cited a tracker
number answering 404 has been rewritten in ruling C+D's form C (comment
5749154545 on objectstack-ai#19123): **160 sites on 151 lines in 45 files, covering 47
numbers (152 lines rewritten)**. Each rewritten line now cites the
object this repository controls that decided the matter:

- an ADR or ruling record where one exists;
- otherwise the commit in `origin/main` history that decided it.

Each line also says in its own words what that object decided. Where
nothing answers, the sentence keeps its reason in words and the number
is gone: that happened for four numbers.

Only comments changed. Every file keeps its line count (152 lines out,
152 in), so no line citation into these files moves. No code token moves
(see the guard below). String literals carrying a dead number are
tokens: 30 such sites are left as they were and listed below.

**No citation number is added.** Every tracker number on an added line
was already on the line it replaces. That includes the two PR numbers
now standing beside their shas as convenience links: PR objectstack-ai#6900 beside
`b5404f496`, and PR objectstack-ai#7211 beside `1507ba356`.

## Census: this stage's two areas, before and after

**Instrument.** This is PR objectstack-ai#20226's instrument: REST `GET
/repos/objectstack-ai/objectstack/issues/N` without following redirects,
over every distinct in-repo number cited in the two areas. The
population is:
- bare `#N`, `objectstack#N`, `framework#N`, and the `pre-#N` /
`post-#N` spellings, with N of 100 or more;
- excluding the ordinal heads the citation gate declares (Prime
Directive, `PD`, decision `batch`) and `summon`.

**Controls.** The lit controls were `objectstack-ai#16862`, `objectstack-ai#16847` and `objectstack-ai#17698`. The
dead controls were `objectstack-ai#16714`, `objectstack-ai#16715` and `objectstack-ai#16697`. They were probed at
the start, after every 100 numbers and at the end: 6 checkpoints per
run. They read 18 of 18 lit (200) and 18 of 18 dead (404) in both runs.

| reading | tree | numbers probed | 200 | 404 | 301 or other | dead
sites | kernel | contracts | lines | files | dead numbers |
|---|---|---|---|---|---|---|---|---|---|---|---|
| before | base `6a6a17b62`, probed 2026-09-27T20:14Z to 20:16Z | 445 |
398 | 47 | 0 | **190** | 106 | 84 | 180 | 45 | 47 |
| after | head (probe at `eda5c6b27`, 2026-09-27T21:24Z to 21:26Z;
source identical at the final head) | 415 | 398 | 17 | 0 | **30** | 18 |
12 | 29 | 14 | 17 |

**Before, by class.**
- 73 non-test docblock sites and 26 non-test line comments.
- 22 test docblock sites and 39 test line comments.
- 28 test string sites (describe and it titles, one assertion message).
- 2 non-test strings.

**After.** Only the 30 string sites remain. There are 0 comment sites.
The head probe found no number newly dead since the base probe.

PR objectstack-ai#20226's area table read kernel 105 and contracts 81 at an earlier
base. This census reads 106 and 84 because it also counts the `pre-#N` /
`post-#N` spelling: 3 dead sites.

## Per-number table

The site counts give comments rewritten and strings left. The kind
column says what each line now cites:
- commit: the commit whose diff made the decision the line describes
(read in each diff, not only in the subject);
- ADR: the recorded decision;
- dropped: the reason is kept in words and the number removed.

| number | sites / files | rewritten / left (string) | anchor | kind |
|---|---|---|---|---|
| `objectstack-ai#5970` | 2/1 | 2/0 | `97e7e3caa`: `ActionSchema.visible` gains the
boolean arm | commit |
| `objectstack-ai#6083` | 1/1 | 1/0 | ADR-0122 phase 2, `53068c130`: find and findOne
pinned to the parsed state | commit (ADR named) |
| `objectstack-ai#6206` | 12/5 | 12/0 | `d7e0b4212`: maintainer ruling 2026-08-07,
enforcement takes the full envelope with no per-site subset. One site
cites `8e13ca876`, the route half that restored the five dropped fields.
Two name the ruling in words where the same block already cites the sha
| commit |
| `objectstack-ai#6216` | 2/2 | 2/0 | `f586f1a89`: one ExecutionContext assembler,
closed field-set pin | commit |
| `objectstack-ai#6300` | 2/1 | 2/0 | `74155c735`: find and findOne accept the author
state | commit |
| `objectstack-ai#6361` | 1/1 | 1/0 | `90bbf2510`: notification-list `cursor` retired
on both halves | commit |
| `objectstack-ai#6362` | 3/2 | 3/0 | `b5404f496` (PR objectstack-ai#6900 beside it): `connector`
keeps the ADR-0010 envelope | commit |
| `objectstack-ai#6363` | 3/1 | 3/0 | `17d095413`: `unreadCount` counts the whole
inbox, not the window | commit |
| `objectstack-ai#6483` | 6/1 | 6/0 | ADR-0005 whitelist, executed by `ee58392e1`:
nine unratified `allowOrgOverride: true` rolled back | commit (ADR
named) |
| `objectstack-ai#6511` (a PR) | 5/1 | 5/0 | `d7e0b4212`, its squash commit | commit |
| `objectstack-ai#6523` | 7/3 | 6/1 | `aa4b90d9a`: sharing and approval enforcement
take the full ExecutionContext | commit |
| `objectstack-ai#6640` | 2/2 | 2/0 | `2ab1257c9`: `preserveAudit` is UPDATE-only,
with a loud INSERT warn | commit |
| `objectstack-ai#6723` (a PR) | 1/1 | 1/0 | `8ad609c69`, its squash commit:
getObject's declared answer | commit |
| `objectstack-ai#6725` | 6/2 | 4/2 | `1507ba356` (PR objectstack-ai#7211 beside it): facade object
writes reach the map its reads use | commit |
| `objectstack-ai#6745` | 2/1 | 2/0 | `7a5ef0008`: the getObject-equals-get
conformance pin | commit |
| `objectstack-ai#8715` | 3/3 | 3/0 | `2c86fe3ea`: the retirement pin form over
`export-origins/` | commit |
| `objectstack-ai#8794`, `objectstack-ai#8836` | 1/1 each | 1/0 each | `1850ebbb0`: measured the
filter-reuse invariant and pinned it | commit |
| `objectstack-ai#10194` | 7/2 | 6/1 | `2306a765c`: theme and analytics_cube bound at
the /meta door | commit |
| `objectstack-ai#10238` | 1/1 | 1/0 | none: whether cube authoring is live end to end
is still its own measurement (`559041d39` leaves it open) | dropped |
| `objectstack-ai#10338` | 2/1 | 1/1 | `d2619fd0c`: `ApiEndpoint.target` optional, the
publish gate holds the requirement | commit |
| `objectstack-ai#10485` | 5/2 | 5/0 | `35ad101bc`: `themes` carrier and ThemeSchema
retired | commit |
| `objectstack-ai#10627` | 3/2 | 3/0 | `be21955ba`, whose message records that
controlled census | commit |
| `objectstack-ai#10724` | 16/5 | 15/1 | `be21955ba`: nine dead `contributes` members
tombstoned | commit |
| `objectstack-ai#10726` | 6/3 | 4/2 | `bc56e1881`: `contributes.routes` retired,
ruled Option B | commit |
| `objectstack-ai#10812` | 2/2 | 2/0 | none: the cloud leg's clean close is kept as
its date (2026-08-24, which `be21955ba` records) | dropped |
| `objectstack-ai#11071` | 1/1 | 1/0 | `50fb191dc`: `os generate` file names derived
from the registry, with the parity pin | commit |
| `objectstack-ai#11330` | 2/1 | 1/1 | `a9ee98992`: trust-tier text states
publish-gate-only enforcement | commit |
| `objectstack-ai#11331` | 2/1 | 2/0 | none: an open "tracked on" pointer, and the
enforce leg is unbuilt. The lines now say so | dropped |
| `objectstack-ai#11332` | 9/2 | 8/1 | `dce5cd4f0`: three dead manifest containers
retired | commit |
| `objectstack-ai#11333` | 1/1 | 1/0 | `aaacf1d5c`: the commit that corrected the
permissions half | commit |
| `objectstack-ai#11350` | 1/1 | 1/0 | `ece4dad31`, which records the 2026-08-23
entry-nameability ruling | commit |
| `objectstack-ai#11504` | 1/1 | 1/0 | `f90e82024`: `FLOW_INPUT_SCHEMA_INVALID`
registered | commit |
| `objectstack-ai#11741` | 5/2 | 4/1 | `b706af987`: `SendEmailInput.organizationId` |
commit |
| `objectstack-ai#11846` | 11/3 | 7/4 | `0c2334f6c`: preview mode retired | commit |
| `objectstack-ai#12010` | 5/2 | 3/2 | none: that `ConnectionEngineLike` inventory is
described in words | dropped |
| `objectstack-ai#12165` | 1/1 | 1/0 | `b307bfd2a`: the glob-discovery disposition
recorded beside `filePatterns` | commit |
| `objectstack-ai#12248` | 19/4 | 15/4 | `8425c17cc`: the five ruled engine members
adopted, getObject typed | commit |
| `objectstack-ai#13135` | 9/7 | 8/1 | `9e0ba21a1`: paper customization protocol
retired. ADR-0126 section 6 wall 4 stays cited where the line had it |
commit (ADR named) |
| `objectstack-ai#13608` | 2/1 | 2/0 | `fc9ba76a5`: eligibility held at redemption |
commit |
| `objectstack-ai#14143` | 2/2 | 2/0 | `f19475c0a`: the handler-face
`ctx.recordLoadDenied` signal | commit |
| `objectstack-ai#14192` | 4/1 | 0/4 | none rewritten: test titles only | (strings) |
| `objectstack-ai#14722` | 2/1 | 2/0 | `23c72be3c`: pinned the measurement that
refuted that card's premise | commit |
| `objectstack-ai#16559` | 2/1 | 1/1 | `c7aca0dce`: ResumeFailureReport declared once
| commit |
| `objectstack-ai#16786` | 3/2 | 2/1 | `6059b29c0`: `updateById` declares its answer |
commit |
| `objectstack-ai#17147` | 5/2 | 3/2 | `aaacf1d5c`: the granted permission set is
registered and refuses nothing | commit |
| `objectstack-ai#18335` | 1/1 | 1/0 | ADR-0090 D10's 2026-09-16 note: an API key is a
credential | ADR |

Every cited sha resolves to exactly one commit, and every one is an
ancestor of `origin/main` (38 shas, each `merge-base --is-ancestor` exit
0).

## The 30 string sites left as tokens

- **Test titles and one assertion message (28 sites).**
- contracts: `data-engine.test.ts` (4), `objectql-engine.test.ts` (2),
`email-service.test.ts`, `resume-failure-report.pin.test.ts`,
`scoped-context.test.ts` and `sharing-service.test.ts` (1 each).
- kernel: `manifest-unknown-keys.test.ts` (4), `manifest.test.ts` (4),
`preview-mode-retirement.test.ts` (4, one of them an assertion message),
`plugin-runtime-tier-truthful-text.test.ts` (3), and 1 each in
`metadata-customization-retirement.test.ts`,
`metadata-type-api-registration.test.ts` and
`metadata-type-schemas.test.ts`.
- **Non-test strings (2 sites).** Two `why:` strings on rows of the
exported `METADATA_ROUNDTRIP_CASES` table in
`contracts/metadata-service-roundtrip-conformance.ts` (lines 194 and
202). They ship in the package as data. No runtime path prints them to
an author: both test drivers title each case by its `id`. So they are
not author-shown text in the form D sense, and they are not rewritten
here.

## Mechanical guard: no code token moves

The check is a comments-stripped token comparison, base `6a6a17b62`
against the head. It uses the TypeScript parser's leaf tokens, so
template literals are scanned in context, and it excludes JSDoc nodes.
It ran over all 45 touched `.ts` files.

- Real run: 60,827 base tokens, **0 files with a token change** (exit
0).
- Comment-insertion control: 0 changes, as expected (exit 0).
- Positive control (a declaration inserted): 1 file flagged (exit 1).
- Positive control (one digit changed inside a test-title string): 1
file flagged (exit 1).

## Changeset

This change ships bytes, so a `patch` changeset for `@objectstack/spec`
is included; it says only that provenance comments were re-anchored.

Measured on the built package: rewritten docblocks reach
`dist/**/*.d.ts`. For example, `8425c17cc`, `17d095413`, `aa4b90d9a` and
`fc9ba76a5` each appear in 1 declaration file, and the positive control,
a pre-existing `notification-service` docblock sentence, appears in
`dist/contracts/index.d.ts`. Rewritten comments also reach the bundled
`.js`: `be21955ba` appears in 20 files. The `src/**/*.zod.ts` sources
ship verbatim through `files[]`.

## Gates (head `ebbea0b6e`)

- **Citation judging pass, run as CI runs it:** `pnpm
check:issue-citations && node scripts/check-issue-citations.mjs` exits
0. It judged 23 citations: 21 resolve and 2 resolve as pull requests
(the two convenience links).
- **Doc authoring:** `pnpm check:doc-authoring` exits 0.
- **Derived gates:** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` derived 86 families, and all 86 exit
0. `--ran` reports 86 run, 0 NOT MEASURED, 0 unrun, and exits 0. Five of
them (`check:doc-formula-expressions`, `check:dual-build-cjs-loads`,
`check:i18n`, `check:lean-entry-closure`, `check:type-check-debt`) first
exited 3, PREREQUISITE NOT MET. They exited 0 after a full `turbo run
build` of `./packages/*` (71 tasks, exit 0, under the shared verify
lock).
- **Build, tests, typecheck:**
  - `pnpm --filter @objectstack/spec build` exits 0.
- `vitest run src/kernel src/contracts` in `packages/spec`: 99 files and
1,608 tests pass. That covers all 24 touched test files and every test
here that reads contract source text.
- `pnpm --filter @objectstack/spec typecheck` exits 0, including
`check:test-typecheck`.

## Acceptance notes

- **Base.** The branch is 5 commits behind `origin/main` (`4e0f72e8d`).
None of those commits touches `kernel/`, `contracts/` or any file here,
so there was no merge.
- **No author-shown string in scope.** Nothing in these two areas is
form D's; the migration-entry fields belong to objectstack-ai#20233.
- **Instrument note, not filed.** The citation gate reads `pre-#N` and
`post-#N` as a cross-repository qualifier (`pre-`), so it never judges
them. In these two areas that is 18 sites at base, 3 of them dead. This
census counted them by hand.
- **`framework#N` is NOT MEASURED as a repository.**
`objectstack-ai/framework` answers 403 to this session's REST gate. The
five numbers cited that way resolve 200 in this repository. None of them
is in the dead set.
- **Seat 2's pointer.** The 21 `objectstack-ai#13003` notes in
`packages/spec/liveness/permission.json` are outside this stage, as the
claim records.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants