Skip to content

chore: version packages - #17076

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main
Open

github-actions[bot] wants to merge 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

The changelog information of each package has been omitted from this message, as the content exceeds the size limit.

@objectstack/cli@17.5.0

@objectstack/client@17.5.0

@objectstack/core@17.5.0

@objectstack/driver-memory@17.5.0

@objectstack/driver-sql@17.5.0

@objectstack/driver-sqlite-wasm@17.5.0

@objectstack/driver-turso@17.5.0

@objectstack/formula@17.5.0

@objectstack/lint@17.5.0

@objectstack/mcp@17.5.0

@objectstack/metadata@17.5.0

@objectstack/metadata-core@17.5.0

@objectstack/metadata-protocol@17.5.0

@objectstack/objectql@17.5.0

@objectstack/platform-objects@17.5.0

@objectstack/organizations@17.5.0

@objectstack/plugin-approvals@17.5.0

@objectstack/plugin-audit@17.5.0

@objectstack/plugin-auth@17.5.0

@objectstack/plugin-hono-server@17.5.0

@objectstack/plugin-security@17.5.0

@objectstack/rest@17.5.0

@objectstack/runtime@17.5.0

@objectstack/sdui-parser@17.5.0

@objectstack/service-analytics@17.5.0

@objectstack/service-automation@17.5.0

@objectstack/service-messaging@17.5.0

@objectstack/service-queue@17.5.0

@objectstack/service-storage@17.5.0

@objectstack/spec@17.5.0

@objectstack/trigger-schedule@17.5.0

@objectstack/types@17.5.0

@objectstack/verify@17.5.0

@objectstack/hono@17.5.0

@objectstack/account@17.5.0

@objectstack/setup@17.5.0

@objectstack/studio@17.5.0

@objectstack/client-react@17.5.0

@objectstack/cloud-connection@17.5.0

@objectstack/connector-mcp@17.5.0

@objectstack/connector-openapi@17.5.0

@objectstack/connector-rest@17.5.0

@objectstack/connector-slack@17.5.0

create-objectstack@17.5.0

@objectstack/driver-mongodb@17.5.0

@objectstack/metadata-fs@17.5.0

@objectstack/observability@17.5.0

@objectstack/embedder-openai@17.5.0

@objectstack/knowledge-memory@17.5.0

@objectstack/knowledge-ragflow@17.5.0

@objectstack/plugin-dev@17.5.0

@objectstack/plugin-email@17.5.0

@objectstack/plugin-pinyin-search@17.5.0

@objectstack/plugin-reports@17.5.0

@objectstack/plugin-sharing@17.5.0

@objectstack/plugin-webhooks@17.5.0

@objectstack/service-cache@17.5.0

@objectstack/service-cluster@17.5.0

@objectstack/service-cluster-redis@17.5.0

@objectstack/service-datasource@17.5.0

@objectstack/service-i18n@17.5.0

@objectstack/service-job@17.5.0

@objectstack/service-knowledge@17.5.0

@objectstack/service-package@17.5.0

@objectstack/service-realtime@17.5.0

@objectstack/service-settings@17.5.0

@objectstack/service-sms@17.5.0

@objectstack/trigger-api@17.5.0

@objectstack/trigger-record-change@17.5.0

@objectstack/console@17.5.0

@objectstack/example-crm@4.0.97

@objectstack/example-multi-package@0.0.4

@objectstack/example-showcase@0.3.19

@objectstack/example-todo@4.0.97

@objectstack/example-embed-objectql@0.0.37

@objectstack/dogfood@0.0.45

@objectstack/downstream-contract@0.0.43

@objectstack/http-conformance@0.1.5

@github-actions
github-actions Bot force-pushed the changeset-release/main branch from ca34d66 to 83e005e Compare September 9, 2026 12:15
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 83e005e to 25e2bf8 Compare September 9, 2026 18:13
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 3 times, most recently from d02da01 to f21afd1 Compare September 10, 2026 12:15
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 3 times, most recently from 6ce105b to 7d29fcf Compare September 11, 2026 06:17
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 3 times, most recently from c821cfc to f769cd4 Compare September 12, 2026 00:25
@claude claude Bot mentioned this pull request Sep 12, 2026
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from f769cd4 to 70c10e2 Compare September 12, 2026 06:16
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 70c10e2 to c26a619 Compare September 12, 2026 12:14
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
…e and the pending changesets (objectstack-ai#17851)

The M9.1 / M9.2 expression phases — including the promise that `ast`
becomes required in build output — were asserted across the tree and
defined in no ADR. Decision batch objectstack-ai#123 item 1 (director seat,
2026-09-12) ruled option **B**, maintainer verbatim 「同意」: the phase
assertions are removed, and `ast` stays an accepted optional persisted
form with no promise of becoming required. This PR is the **docs half**
of that ruling — the published docs page and the two still-unconsumed
changesets now state the contract in the present tense: `source` is the
canonical persisted form, `ast` is an optional opaque structured value.
Per the ruling's item 4 (「Files under `packages/spec` and
`packages/formula` are the spec seat's: the `domain:skills` taker edits
docs and coordinates the spec half as a sibling PR by that seat, ⛔ not a
cross-lane rider」), nothing under `packages/` is touched here; the spec
half is a sibling PR by that seat, tracked as objectstack-ai#17849. No ADR is written
— B means there is no phase to define.

Part of objectstack-ai#17323

## Acceptance notes

### Premises, re-taken at this branch's base `758ac409`

1. **HOLDS.** `git grep -l 'M9\.[12]' origin/main` returns exactly seven
files — `.changeset/blank-node-condition-refused-at-registration.md` (1
hit), `.changeset/flow-edge-condition-evaluated-slot.md` (3 hits),
`content/docs/data-modeling/formulas.mdx` (1 hit),
`packages/formula/src/cel-engine.ts`,
`packages/formula/src/normalize.ts`, `packages/spec/CHANGELOG.md`,
`packages/spec/src/shared/expression.zod.ts`. The last four are the spec
seat's and are untouched here; after this PR the repo-wide count is
those four and nothing else.
2. **HOLDS, with a timing note.** Both changesets are present and
unconsumed under `.changeset/` at this base. ⚠️ The standing Version
Packages PR objectstack-ai#17076 (`changeset-release/main`, bot-authored) lists both
of them as `removed` — it is the consuming side. So this correction has
to land **before** that PR does; once a release consumes these files,
the ruling's item 3 routes the same correction to a `CHANGELOG.md`
erratum instead, which rides the spec half.
3. **HOLDS.** `formulas.mdx` :27 (`deleted in M9`), :111 (`M9.9b`) and
:583 (`M9.5`) are other milestone references and are byte-identical —
they do not appear in the diff, and `git grep -c 'M9' --
content/docs/data-modeling/formulas.mdx` still reports 3 (now at :27 /
:112 / :584, shifted by the one line this PR adds).
4. **HOLDS.** All 22 open PRs' file lists were re-scanned; none names
the three files, with the single qualification in premise 2 — objectstack-ai#17076
lists the two changesets as consumed, which is not a competing edit.

### The sentences, before → after

**A · `content/docs/data-modeling/formulas.mdx` :86-87**

```
- artifact always contains the full envelope (and, after M9.2, the AST).
+ artifact always contains the full envelope: `source` is the canonical persisted
+ form, and `ast` is an optional opaque structured value.
```

**B1 · `.changeset/flow-edge-condition-evaluated-slot.md` :30** — inside
the blockquote that reproduces the refusal sentence:

```
- > engine evaluates `source` (the canonical persisted form of phase M9.1) and
+ > engine evaluates `source` (the canonical persisted form) and
```

**B2 · `.changeset/flow-edge-condition-evaluated-slot.md` :44-48** — the
phase-2 promise itself:

```
-   the persistence contract (`source` OR `ast`), whose docblock declares that
-   `ast` becomes required in build output at phase M9.2. When AST-only
-   evaluation lands, `EvaluatedExpressionSchema` is the one place to relax, and
-   every evaluated slot follows.
+   the persistence contract (`source` OR `ast`), where `ast` is accepted as an
+   optional opaque structured value and carries no promise of becoming required.
+   If AST-only evaluation is ever chartered, `EvaluatedExpressionSchema` is the
+   one place to relax, and every evaluated slot follows.
```

**B3 · `.changeset/flow-edge-condition-evaluated-slot.md` :73**

```
- carried only `ast` has no evaluable form under M9.1: author its `source`. A
+ carried only `ast` has no evaluable form: author its `source`. A
```

**C · `.changeset/blank-node-condition-refused-at-registration.md` :33**
— the eighth site, which neither the card nor the ruling named. **What
it said:** the same verbatim blockquote of the refusal sentence that B1
carries, with the identical `(the canonical persisted form of phase
M9.1)` parenthetical; it is the only M9 reference in that file, and it
gets the identical treatment:

```
- > engine evaluates `source` (the canonical persisted form of phase M9.1) and
+ > engine evaluates `source` (the canonical persisted form) and
```

Nothing else in the three files is touched: 3 files, 9 insertions, 8
deletions, and the changeset frontmatter (package and bump level) of
both changesets is unchanged.

### D · Verification

| reading | result |
|---|---|
| `git grep -l 'M9\.[12]' -- content .changeset` | 0 files (exit 1, no
match) |
| control — `git grep -c 'M9' --
content/docs/data-modeling/formulas.mdx` | still `3` (the :27 / :112 /
:584 milestones) |
| control — the pattern still matches elsewhere, so it is not a dead
pattern: `git grep -c 'M9\.[12]'` | 4 files, all the spec seat's |
| dark control — `git grep -c 'M91zzz' -- content .changeset` | 0 (exit
1), so the pattern does not match everything |
| `grep -naP` for raw control bytes over the three files | clean (exit
1) |

### Coordination with the spec half, objectstack-ai#17849

The blockquote edited in B1 and C is a **verbatim quote of an exported
constant** — `EVALUATED_EXPRESSION_SOURCE_REQUIRED` in
`packages/spec/src/shared/expression.zod.ts`, which still carries `of
phase M9.1` on `main`. This PR drops exactly that phase clause and keeps
`(the canonical persisted form)`, because "`source` is the canonical
persisted form" is the present-tense contract the ruling's item 1 names.
For the quote to stay a quote, the spec half must land that same wording
in the constant. Flagged rather than worked around: `packages/spec` is
not this lane's, per item 4.

### Changeset: `skip-changeset`, measured

Two existing changesets are edited and none is added, so the changeset
count this PR adds is 0 and the label is the applicable rule
(`AGENTS.md` Post-Task Checklist step 3: the label is for a diff that
publishes nothing from any released package). Measured rather than
assumed:

- no published package's `files[]` ships `content/**` or `.changeset/**`
— 0 matching entries across every non-private workspace manifest;
- the added strings (`carries no promise of becoming required`, `is an
optional opaque structured value`) appear in 0 published paths;
- positive control — `canonical persisted form` **does** hit a published
path (`packages/spec/CHANGELOG.md`,
`packages/spec/src/shared/expression.zod.ts`), so the measurement is not
vacuous.

The publication this correction affects is already declared by the two
changesets it edits (`@objectstack/spec` minor,
`@objectstack/service-automation` minor); a third changeset would
declare a release of its own for a prose correction that rides theirs.
The `CHANGELOG.md` erratum for the already-published M9.2 text is the
ruling's item 2 and belongs to the spec half.

### Gates

Derived in this worktree with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` (no paths — the tool took
the change set from git itself at `9e12d4a62` vs merge base
`758ac4097`): **51 commands**. Every one was run; reconciliation with
`--ran` reports **51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN**, all
exit 0.

Four of them first exited `3` / `1` as **PREREQUISITE NOT MET** —
nothing measured, unbuilt workspace packages, not findings:
`check:doc-formula-expressions` and `check:doc-security-posture`
(`@objectstack/formula`, `@objectstack/lint` unbuilt),
`check:docs-transcript-drift` (same), and `check:skill-examples`
(`packages/client-react/dist` held no `.d.ts`). After `pnpm exec turbo
run build --filter='@objectstack/lint...'
--filter='@objectstack/formula' --filter='@objectstack/client-react...'
--concurrency=2`, all four are exit 0. Verdict lines, as each gate
printed them:

```
✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (2 non-breaking changeset(s) seen).
✓ This diff introduces no `major` bump.
✓ No empty-frontmatter changeset introduced by this diff (2 declaring changeset(s) added).
✓ doc authoring guard: 401 files clean — no bare metadata literals.
check-nul-bytes: OK (scanned 8476 text file(s) -- 8476 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).
✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 438 files / 1374 TS blocks judged clean by @objectstack/formula.
✓ check-docs-transcript-drift: 4 declared transcript value(s) across 402 page(s) under content/docs/ equal what the registry derives today, and no undeclared block quotes one.
```

`node scripts/check-changeset-fixed.mjs` was run as well and is exit 0 —
the derivation flags its roster as living under `.changeset`, one of
this PR's paths, so its silence is evidence in neither direction until
run. It reads `.changeset/config.json` and the workspace manifests,
neither of which this PR touches.

Repo-wide scans (`pnpm lint` and the rest) are CI's, as are the two
path-scheduled CI jobs and the 11 declared-wide families the derivation
names as unplaceable locally.

### Noted, not filed

- `scripts/check-adr-0087-registration.mjs`'s pass line labels every
**skipped** changeset "non-breaking" (`${result.skipped.length}
non-breaking changeset(s) seen`), so the two changesets here — both
declared breaking at base and skipped as inherited stock by the
specified `M breaking at head, already breaking at base` row — are
reported as non-breaking. The verdict is correct and the row is a pinned
self-test case; only the summary wording under-describes. A pass-line
wording nit, not a defect class, not a contract violation and not an
authoring trap, so no card. Taker: none — no queued PR touches that
script.

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

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
…used to be (objectstack-ai#17838)

The Protocol Domains table in `AGENTS.md` still listed a `Cloud` /
`cloud/` row after the cloud control-plane contracts left the
open-source spec and the package & marketplace format moved to
`packages/spec/src/marketplace/`, published as
`@objectstack/spec/marketplace`. The row sent a reader to a directory
the tree no longer has, and omitted the one that replaced it. This
replaces that one row with a `Marketplace` / `marketplace/` row at the
same alphabetical position (after `Kernel`), described from the
directory's actual modules rather than from the card's proposal. One
line in, one line out — 1075 lines before and after. Docs-only,
`skip-changeset`.

Fixes objectstack-ai#17370

## Acceptance notes

### The row

```
-| `Cloud` | `cloud/` | Multi-tenant, deployment, environment |
+| `Marketplace` | `marketplace/` | Package, Version, Listing, Install, Template |
```

### Premise findings, re-taken on `origin/main` `51b024a16` (the PM took
them on `d79f2499`; `main` advanced by two `docs(pm)` commits, objectstack-ai#17828
and objectstack-ai#17823, neither touching `AGENTS.md`)

1. **Holds.** `AGENTS.md:657` read `| `Cloud` | `cloud/` | Multi-tenant,
deployment, environment |` directly after the `Kernel` row at `:656`;
the file is 1075 lines.
2. **Holds.** `git ls-tree -d origin/main packages/spec/src/marketplace`
answers `040000 tree 3f19482…`; `packages/spec/src/cloud` answers
nothing. `packages/spec/package.json` exports `./marketplace`, and has
no `./cloud`.
3. **Holds.** `git grep -ln "Multi-tenant, deployment, environment"
origin/main` hits only `AGENTS.md`; `git grep -ln "Protocol Domains"
origin/main -- scripts .github packages/spec/scripts` hits nothing. No
gate reads this table.
4. **Holds, re-measured.** All 22 open PRs' file lists scanned at this
commit, fully paginated (PR objectstack-ai#17076 is the standing Version Packages PR
at 383 changed files — four pages read). None touches `AGENTS.md`.
5. **FALSIFIED — the dispatch's line-width premise.** The dispatch named
"AGENTS.md's own line-width rule, Prime Directive objectstack-ai#8" wrapping at ~84–90
bytes. There is no such rule. Prime Directive objectstack-ai#8 is **North Star
alignment**; `AGENTS.md` carries no line-width rule at all. The real
120-byte budget is `MAX_LINE_BYTES` in
`scripts/pm/check-skill-line-ratchet.mjs`, and it **exempts a markdown
table row by shape** (`EXEMPTION_CLASSES.table`: "a wrapped `|` row is a
different table"). What actually binds a table row is that script's
**second** ratchet, `MAX_TABLE_ROW_BYTES`, pinned for `AGENTS.md` at
**768 bytes**, shrink-only, headroom 0. The new row is far under it, and
the gate's own verdict lines confirm both pins are untouched:

   ```
✓ check-skill-line-ratchet: AGENTS.md: widest table row is 768 bytes
(pin 768; headroom 0).
✓ check-skill-line-ratchet: AGENTS.md is 1075 lines (ceiling 1075;
headroom 0).
   ```

The dispatch's *operative* instruction — stay within the table's own
widest row — was honoured anyway; see the width note below.

### Work item B — other `cloud/` references in AGENTS.md

`git grep -n "cloud/" origin/main -- AGENTS.md` returns exactly one hit:
line 657, the row being replaced. Nothing else in the file to report,
and nothing else was touched.

### The description, verified against the directory

`git ls-tree -r --name-only origin/main packages/spec/src/marketplace`
lists ten files — five modules and five test files:

```
index.ts
marketplace.zod.ts          marketplace.test.ts
package.zod.ts              package-namespace.test.ts
package-version.zod.ts      package-l10n.test.ts
package-l10n.ts             template-manifest-id.test.ts
template-manifest.zod.ts
```

The card proposed 「Package identity & versions, marketplace listing /
publish / install format, template manifests」. That description is
**accurate** — it does not overstate — but it is 132 bytes as a row,
against a table whose widest row is 84, and its `&` / ` / ` punctuation
is out of register with its neighbours, which are bare comma-separated
noun lists of the domain's principal schemas (`Data` → "Object, Field,
FieldType, Query, Filter, Sort"; `Security` → "Permission, Role,
Policy"). So it was shortened into that register, one noun per real
schema family, each traceable to a module's top-level exports:

| Noun | Module | Principal exports |
|:---|:---|:---|
| `Package` | `package.zod.ts` | `PackageSchema`,
`PackageTranslationsSchema`, `CreatePackageRequestSchema` |
| `Version` | `package-version.zod.ts` | `PackageVersionSchema`,
`PackageManifestSchema`, `PublishPackageVersionRequestSchema` |
| `Listing` | `marketplace.zod.ts` | `MarketplaceListingSchema`,
`PackageSubmissionSchema`, `MarketplaceSearchRequestSchema` |
| `Install` | `marketplace.zod.ts` | `MarketplaceInstallRequestSchema`,
`MarketplaceInstallResponseSchema` |
| `Template` | `template-manifest.zod.ts` | `TemplateManifestSchema` —
the on-disk `objectstack.manifest.json` descriptor |

`package-l10n.ts` is the listing-localisation resolver over
`PackageTranslations` and folds under `Package`; the neighbouring rows
do not enumerate helper resolvers either (`Shared` → "Error maps,
normalization utilities").

### Byte width of the new row versus the table's widest

| Row | Bytes |
|:---|---:|
| New `Marketplace` row | **81** |
| Table's widest row — `UI` (`:649`) | 84 |
| Old `Cloud` row (replaced) | 62 |
| `MAX_TABLE_ROW_BYTES` pin for AGENTS.md (the gate) | 768 |

The new row is 3 bytes under the table's own widest and 687 under the
enforced pin.

### Gates

Derived in this worktree with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` (no paths — the tool takes
its own change set from the merge base). 14 families derived, **14 run,
all exit 0**:

```
node scripts/check-closing-keyword-parity.mjs             :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs                :: exit 0
pnpm check:agent-test-spelling                            :: exit 0
pnpm check:docs-audit-scope                               :: exit 0
pnpm check:driver-memory-census                           :: exit 0
pnpm check:nul-bytes                                      :: exit 0
pnpm check:pm-governed-merges                             :: exit 0
pnpm check:pm-governed-prose                              :: exit 0
pnpm check:pm-skill-id-lint                               :: exit 0
pnpm check:pm-skill-ratchet                               :: exit 0
pnpm check:refd-timer-probe                               :: exit 0
pnpm check:required-contexts                              :: exit 0
pnpm check:watch-hint-literal                             :: exit 0
```

Reconciled: `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --ran RANFILE` (exit codes recorded per
family) →

```
✓ dispatch-gates --ran: 14 derived famil(ies) accounted for — 14 run, 0 NOT-MEASURED
  (a DERIVED zero — all 14 recorded an exit code and none of them is 3).
```

All gate readings above were taken at `f68b09653`, the final commit on
this branch.

No build or test family is owed: the diff touches no package, so the
closure build is empty and no package's `pnpm test` / `pnpm typecheck`
is in scope. Control-byte self-scan beyond `check:nul-bytes`: `grep -naP
'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' AGENTS.md` exits 1 with zero output.

### Changeset

`skip-changeset`. Measured, not assumed: of the 76 tracked package
manifests, zero published package lists anything matching `AGENTS` in
its `files[]`, against a positive control of 70 published packages that
do list `README`. `AGENTS.md` is a repo-root instruction file and ships
in no tarball, so this PR publishes nothing.

### Governed surface

`AGENTS.md` is a governed surface (Prime Directive objectstack-ai#14). This PR stays a
**draft**; it is never flipped ready, never queued, and auto-merge is
never armed by this seat. The PM places the four-piece and the
maintainer merges.

## 维护者速读(草稿)

**改了什么** — `AGENTS.md` 的 Protocol Domains 表里那一行 `Cloud` / `cloud/` 换成了
`Marketplace` / `marketplace/`,位置不变(仍在 `Kernel`
之后,按字母序),描述按目录里实际有的五个模块重写。整个 PR 就这一行,进一行出一行,文件 1075 行前后不变。

**为什么改** — objectstack-ai#16325 把云控制面的协议移出开源 spec(option B「cut by
owner」,维护者「同意」),包与市场格式搬到了
`packages/spec/src/marketplace/`。那一行从此指着一个不存在的目录,并且漏掉了顶替它的那个。没有任何门禁读这张表,所以它只会一直烂着,不会变红——这正是要人来修的原因。

**风险与代价(含回滚)** — 风险接近于零:纯文档一行,不触碰任何包,不发布任何东西,14 个派生门禁全绿。回滚就是把这一行改回去,一次
revert 即可,没有任何下游依赖。唯一需要留意的是这是受管面,必须由维护者手工合并。

**席位意见** — (留空,待席位定稿)

**你要做的** — 确认 `Marketplace` 行的描述用词是否合你的意:目前是 `Package, Version, Listing,
Install, Template`,比卡片原提案短,理由是要和表里其他行同一种写法(裸名词列表)、同一个宽度量级(81 字节,表内最宽
84)。如果你更想保留卡片原来那句更长的描述,告诉我,我改。确认后由你手工合并。

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

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
…count (objectstack-ai#18257)

Fixes objectstack-ai#18237

H64 keyed on the author account. The rule it was built on had already
been superseded: write identity follows the CHANNEL, the REST actor is
`claude[bot]` **or** a user per session, and `user.login` records the
token rather than the seat — attribution is the `session_` id in the
text (`.claude/skills/pm-dispatch/references/rest-channel.md` :54,
`.claude/skills/pm-dispatch/SKILL.md` :98). So the row fired on
compliant REST writes from user-token sessions, told their authors the
write had gone through the MCP GitHub tool, and prescribed a re-post
through the REST proxy that lands under the same login and fires again.

This re-keys the row onto the attribution the landed rule actually
requires. One file, `scripts/pm/check-half-states.mjs` (non-governed PM
tooling; `check-governed-merges.mjs --test` on this file list reads `0
of 1 path(s) hit the register`).

## The measurement first — the discriminator the card doubted does not
exist

The PM's mechanism assumption P1 was that
`performed_via_github_app.slug` tells the MCP tool from the REST proxy.
Measured with GET-only reads on live rows, 2026-09-15:

| row | `user.login` | `user.type` | `performed_via_github_app` |
|---|---|---|---|
| comment 5673548571 on objectstack-ai#7623 — REST-proxy write, App token |
`claude[bot]` | `Bot` | `{ id: 1236702, slug: 'claude', name: 'Claude'
}` |
| comment 5673265919 on objectstack-ai#17076 — REST-proxy write, user token |
`os-warren` | `User` | `{ id: 1236702, slug: 'claude', name: 'Claude' }`
|
| comment 5673413139 on objectstack-ai#18237 — REST-proxy write, user token |
`os-warren` | `User` | `{ id: 1236702, slug: 'claude', name: 'Claude' }`
|

And the four specimens H64 was built from, all read the same slug:
objectstack-ai#18045 (`os-project-manager` / `User`), objectui#9404
(`os-project-manager` / `User`), PR objectstack-ai#18051 (`os-project-manager` /
`User`), comment 5652138683 on objectui#9370 (`os-tesla` / `User`); with
the clean control comment 5654046782 (`claude[bot]` / `Bot`).

**P1 is falsified.** The field names the App whose credential signed the
write, never the tool. The first two rows above are both REST-proxy
writes differing only in the token class the session was handed, and
they are byte-identical in this field. So no channel is inferred
anywhere in this family any more, and `artefactChannel`'s docblock now
says what it does read: an App credential versus none. Following P1's
own instruction for this outcome, the MCP half of the seat direction
(candidate (i)) collapses — it has no readable population — and
candidate (ii) is the whole firing row.

## What fires now

A seat/dev-signed artefact — a claim, a report, a contract review, a
filing header — carrying **no `session_` id anywhere in its text**. The
text asserts a seat or a dev wrote it; nothing says which session, and
the author field records only the token. Remedy: the owner gives the
artefact its id (an edit in place is enough). The account is explicitly
stated not to be the repair.

A structural consequence worth naming: two of the six signature forms
**are** session ids (the bare id in the head window, and the attribution
footer's `claude.ai/code/session_` URL), so a text matching either
carries its attribution by construction and can never fire. The firing
population is the other four forms with no id anywhere. The id test
reads the whole body while the signature's head window stays narrow —
pinned as a case.

## The exposure is not relaxed — it moved to where it costs nothing

The addendum stands: a suspended user account 404s everything it
authored, measured on this board. Nothing here relaxes it. It is now
reported as an **informational count plus a login roster** inside the
H64 summary clause, on every run, with no remedy named and no row filed.

That is P5's first option, chosen for the reason P5 gives: no act
available to a user-token session moves its content to the App, because
the token class is handed to a session at start rather than chosen at
write time. A row naming no remedy re-files every sweep at full weight
against an anchor that trimmed 423 of 441 rows. The clause states the
same fact for free, unconditionally, and is strictly **more** visible
than the old rows were — those competed for the cap and were trimmed; a
clause is not.

## Board measurement, before and after (live sweep, GET only)

| reading | before (`ecf91cb4`) | after (`c509364b`) |
|---|---|---|
| texts read / signed | 1697 / 873 | 1703 / 875 |
| finding population | 671 user-authored | 116 naming no session id |
| judged (on/after the pin) | 70 | 26 |
| rows filed (cap 10) | 10 | 10 |
| census behind the pin | 601, back to 2026-08-05T19:32:57Z | 90, back
to 2026-08-08T13:49:21Z |
| informational exposure | not reported | 671 texts, 17 logins, 3 PAT, 3
unread channel |

The two sweeps ran ~40 min apart, so the corpus moved slightly on its
own (1697 to 1703 texts).

**Reverse verification on the live board.** Every row the card named as
a false positive is gone: comments 5673315903 (objectstack-ai#17396), 5673859871
(objectstack-ai#17502), 5673413139 (objectstack-ai#18237), 5670954004 (objectstack-ai#13801) and 5671601791
(objectstack-ai#16695) each appear in 0 rows after, having appeared in 1 before.
objectstack-ai#18237's own two rows are gone.

**And the retired test was blind in the other direction too.** Of the 10
rows filed now, 7 are authored `claude[bot]` — for example comment
5674562475 on objectstack-ai#16166 and comment 5674534458 on objectstack-ai#18174, both
`os-dev-report` payloads whose only footer is the platform's bare one,
and card objectstack-ai#18167's `Filed by the ... seat` body. Every one of those is
exactly as unattributable as the ones the old row shouted about, and the
old row could not see any of them. Spot-checked by GET: none carries a
session id anywhere.

## Fixtures — one kept its role, three were re-classified

Each with its reason, as P4 asks:

| fixture | before | after | why |
|---|---|---|---|
| comment 5652138683 (objectui#9370, `os-tesla`) | fires | **fires** |
names its seat by ACCOUNT and carries no session id in 35 lines —
verified against the live comment. It is now the row's live positive
rather than one specimen of four. |
| objectstack-ai#18045 (`os-project-manager`) | fires | clean | its bare session id is
on line 1: attributed. Its lit control is its own silence — strike the
id and it leaves the population entirely, because `Filed and claimed by`
is not the filing header, so the id was its whole signature. Pinned. |
| objectui#9404 (`os-project-manager`) | fires | clean | same id, beside
a filing header that survives id removal — so **this** is the specimen
carrying the lit control (`BODY9404_NOID` fires). |
| PR objectstack-ai#18051 (`os-project-manager`) | fires | clean | its only id is in
the footer on line 45 of 45, and the id test reads the whole body. The
`/pulls` fire control is a filer-signed body with only the platform bare
footer. |
| comment 5654046782 (`claude[bot]`) | clean | clean | now clean for a
different reason: it carries a `Session:` line. The byte-identical
comment under a USER login is also clean, which is the inversion of the
old case. |

Two new fixtures were added, `restBot64` and `restUser64`, carrying the
2026-09-15 fields above, so the indistinguishability is pinned offline
and the channel inference cannot be re-derived from the reader's name.

## Ablation (one-off proof, not a landed test)

Predicted direction: removing the session-id gate from `h64SpeaksAbout`
should turn the attributed-side silences RED, and should not abort the
suite.

- HEAD blob `ac93c610dc39c93444e72605ab45fafb827c6b32`; mutated blob
`35505df98ecef337f80d1ebccc514257a9ff4897` (distinct, so the mutation
reached disk).
- On-disk proof before reading any result: the anchor line count went 1
to 0 and the injected marker count went 0 to 1.
- Ablated run: `8 of 4113 case(s) failed`, exit 1 — and the 8 are
exactly the attributed-side silences (objectstack-ai#18045, objectui#9404, PR objectstack-ai#18051,
the cleared claim, comment 5654046782 under both logins, and the two
structural cases). No abort.
- Restored with `git checkout HEAD --`, under a `trap ... EXIT INT TERM`
with an absolute repo root: `git status --porcelain` empty, `git diff
HEAD` empty, restored blob `ac93c610dc39c93444e72605ab45fafb827c6b32`
equal to HEAD's, injected marker count 0.

## Deviations from the suggested route, stated rather than buried

1. **"The `claude[bot]` fixtures stay clean" does not survive the
re-keying, by design.** A `claude[bot]`-authored claim with no session
id now fires, and a case pins it. The account was the retired test;
keeping the App side categorically clean would keep half the retired
premise alive, and the live board shows 7 of 10 rows are that shape.
2. **`USER_AUTHORED_WRITE_SINCE` was renamed
`UNATTRIBUTED_WRITE_SINCE`** and `h64UserAuthoredSeatContent` became
`h64UnattributedSeatContent`. Both names encoded the superseded premise,
and both are file-local (grepped: no reference anywhere else in either
repo tree). The pin's instant is unchanged.
3. **The summary window anchor changed** from `User-authored seat
content (H64): ` to `Unattributed seat content (H64): `; the window key
`h64SeatSigned` is unchanged, and `summaryClause`'s uniqueness cases
still pass.
4. `artefactChannel` was kept rather than deleted — with corrected
semantics, and used by the exposure clause's PAT/unread split. Deleting
it would have removed the only place the measurement is enforceable.

## Self-test and gates

- `pnpm check:pm-half-states`: **4075 cases before, 4113 after**, all
passing. (The 4075 baseline was read by running the `ecf91cb4` copy of
the file; 7 of its cases fail when it is run outside the tree because
they read sibling scripts by path, which is a harness artefact, not a
baseline failure — in the tree it is green.)
- Gate roster derived with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack`, no paths (change set: 1
path, three-dot vs merge base `ecf91cb44`): 41 commands. 40 ran in the
foreground with exits captured by redirect — **all exit 0**. The first
pass of 14 read exit 3 `PREREQUISITE NOT MET` in a fresh worktree with
no `node_modules`; after `pnpm install` all 14 re-ran green, and no
exit-3 reading is reported here as a measurement.
- `pnpm check:pm-dispatch-gates` was run detached per its own header (it
exceeds the foreground cap), and waited on rather than polled.
- `skip-changeset`: `scripts/pm/**` publishes nothing — no package's
`files[]` ships it.

## Acceptance notes

Out-of-scope observations, noted and not filed:

- The four-form firing population makes every `os-dev-report` comment a
candidate, because the report JSON carries `branch` but no session id
and the platform appends only a bare footer. That is the row working as
the landed rule specifies, not a defect — but if the maintainer would
rather the report template carry the id, that is a change to
`.claude/agents/os-dev.md`, a different (governed-adjacent) surface and
a different card. Successor: the next `domain:skills` card touching the
dev report template. Noted, not filed.
- `H64_ROW_CAP` still binds at 10 with 26 judged findings, so 16
clearable rows are unfiled per sweep. The cap is correct as designed
(the trim eats the tail) and the clause states the full count.
Successor: whoever next revisits `renderMarkdown`'s ordering, which is
the real constraint. Noted, not filed.

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

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 0eb96c7 to 97da562 Compare September 17, 2026 12:19
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 97da562 to 1c0ce17 Compare September 17, 2026 18:14
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 1c0ce17 to 57d6da9 Compare September 18, 2026 00:28
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 57d6da9 to 83dc780 Compare September 18, 2026 06:20
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 83dc780 to 95fe62d Compare September 18, 2026 12:17
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 95fe62d to c38e1ee Compare September 18, 2026 18:17
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 4 times, most recently from 86d01c4 to c279dc3 Compare September 19, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants