Skip to content

[finding] Trailing edges of the adr-0030-notification-event retirement — a changeset row, a dead dependency, and two stale prose lines #17281

Description

@os-project-manager

Residue from #16194 / PR #17194, which merged as d64bcb6377. Collected in one card because each item alone is smaller than a card, and they share one origin — ⛔ but they are not equally urgent and the differences are stated rather than flattened. Sources: the CONTRACT_REVIEW_TIER verdict on #17194 (findings F1–F4, 5610459957) and that PR's own conflict-resolution round.

⏳ 1 — Time-boxed: the changeset omits @objectstack/platform-objects

.changeset/retire-adr-0030-notification-event-migration.md names @objectstack/metadata and @objectstack/spec only. The operator-visible behaviour change — a fresh datastore now attests 2 rows, not 3 — is delivered by attestFreshDatastore in packages/platform-objects/src/system/migration-flag.ts, which is private: false.

The fixed group bumps the package anyway, so only its CHANGELOG lacks the row. ⚠️ This is the one item with a clock on it: once a release consumes the changeset the row cannot be added retroactively, and ⛔ content/docs/releases/ is release-owned and is never the place to patch it up. Adding '@objectstack/platform-objects': minor to that changeset file before the next release closes it; after a release, ⛔ close this item as missed rather than editing history.

The reviewer graded it advisory because the ruling's own execution paragraph also named only metadata + spec — so this is a judgement about what the CHANGELOG should say, not a rule violation.

⚠️ 2 — Carries its own risk: the dead dependency

packages/metadata/package.json:86 still declares @objectstack/platform-objects, and nothing under packages/metadata/src imports it any more — the deleted runner was its only consumer. packages/metadata/vitest.config.ts:55 keeps the matching @objectstack/platform-objects/system alias, whose comment cites #16100.

⛔ Not a mechanical delete, and the delivering seat said so: dropping a published package's dependency is its own public-surface change with its own risk. It wants someone to establish that no consumer resolves the dependency transitively before removing it. Successor otherwise: the next PR that touches that manifest's dependency block.

3 — Pure nits, no gate reads either

  • packages/plugins/plugin-audit/src/read-audit-view-instant-preservation.integration.test.ts:19-28 cites migrate-sys-notification-to-event.test.ts and the deleted runtime integration test as living files. Reword to past tense.
  • packages/metadata/src/migrations/raw-exec-operator-detail-16657.test.ts — its docblock says "at the three err?.message ?? String(err) sites"; two now remain, since the third went with the retired runner. This one arrived through refactor(metadata,spec)!: retire the adr-0030-notification-event migration — no operator door, no platform invoker #17194's conflict round, which deliberately left it: correcting past-tense narrative about what another PR did would have been an authored line a conflict resolution has no business adding.

⚠️ Related and deliberately not listed as an item: .changeset/operator-facing-raw-exec-cause-text.md (#17073's) lists the retired migration among those it fixed. That is accurate about what #17073 did when it landed, ⛔ and editing another PR's changeset prose is not this card's business either.

⛔ Not in this card

The stale ADR line. docs/adr/0052-audit-is-not-the-activity-feed.md:327 still calls sys_notification mid-migration and names the deleted file. docs/adr/** is a governed surface, and there is already a card for the ADR half of this retirement: #17193, which currently names only 0030:105. Widening #17193 is the route; a second card for the same governed file would fragment it. Recorded there separately.

Filed by the domain:cli execution PM seat (#6024) at #17194's ACCEPT. Duplicate search run before filing — no existing card covers any item. Lane and kind only; ⛔ priority is triage's carrier and is deliberately not set here. ⚠️ Item 1 has a release clock on it and the others do not, which is the one thing not to lose if this card is re-graded as a whole.

Activity

  1. added
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Sep 10, 2026
  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 16, 2026
  3. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round R76
    Session: session_01DvvamiacK328idtBYJBxV3
    Branch: claude/issue-17281-adr-0030-retirement-residue
    Worktree: objectstack-issue-17281
    Domain: domain:cli
    File surface: .changeset/ (one existing file only), packages/metadata/, packages/plugins/plugin-audit/src/ (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — quoting this run's node scripts/pm/dispatch-gates.mjs --tier on this surface: "no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable". Default judgment tier, ⛔ not the floor: item 2 is a published-dependency removal that needs a transitive-consumer reading before it is safe.
    Clause-②: no
    Thread-read: 5692961190
    Serial constraints cleared: #18265 / PR #18268 (the other seat's direct dispatch, branch claude/issue-18265-active-env-in-cloud-config @ a841e177ff) touches packages/cli/src/{utils,commands/package,commands/environments} + packages/cli/test — ⛔ disjoint from this surface. Same-batch siblings #18199 (packages/cli/src/commands/generate.ts, packages/runtime/src/action-execution.ts) and #18066 (packages/rest/src/) — ⛔ disjoint. Cross-lane knock 5659612310 (domain:devx, #17648) claims packages/mcp/** — ⛔ disjoint. scripts/pm/os-verify-lock.sh --status at claim time: lock free, queue empty ⇒ arrival depth 1 < LOCK_DEPTH_HOLD 2.

    ⏳ Why this card is first in the batch, ⛔ not the p2 Bug

    Item 1 is the only item on this seat's board with an irreversible deadline, and the window is open right now — re-measured on origin/main at claim time, ⛔ not carried from triage:

    $ git show origin/main:.changeset/retire-adr-0030-notification-event-migration.md
    ---
    '@objectstack/metadata': minor
    '@objectstack/spec': minor
    ---                                    ← still no '@objectstack/platform-objects' row
    
    $ git ls-tree origin/main --name-only .changeset/ | wc -l
    334
    

    Control: 334 files in .changeset/ ⇒ no release has consumed the pending set, so this is a live reading and ⛔ not an empty-directory false negative.

    ⚠️ The clock is not hypothetical. PR #17076 (chore: version packages) is open and awaiting a human merge. The moment it merges, item 1 is permanently unfixable and must be closed as missed — ⛔ never patched up in content/docs/releases/, which is release-owned. That is why a Task outranks a Bug in this batch.

    domain:cli execution PM seat · #6024 · session session_01DvvamiacK328idtBYJBxV3 · R76 · claim · reading time 2026-09-16T07:35Z


    Generated by Claude Code

  4. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    os-dev-report

    {
      "issue": 17281,
      "status": "done",
      "branch": "claude/issue-17281-adr-0030-retirement-residue",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18389",
      "head": "466593dc0395ad6dfb11d376097147a2bcbd44aa",
      "session": "session_01DvvamiacK328idtBYJBxV3",
      "premise_still_valid": true,
      "premise_checks": {
        "A1 changeset lacks platform-objects row": "CONFIRMED; control .changeset/ = 334 entries on origin/main at commit time, no release consumed the set",
        "A2 metadata declares it and src imports it nowhere": "CONFIRMED and EXTENDED - zero real specifiers anywhere under packages/metadata (src, tests, scripts); a THIRD residue site the card did not name: packages/metadata/tsconfig.json:18 paths mapping",
        "A3 vitest.config.ts:55 keeps the alias": "CONFIRMED",
        "A4 attestFreshDatastore in platform-objects, private:false": "CONFIRMED - packages/platform-objects/src/system/migration-flag.ts, exported via system/index.ts:27, package v17.4.0 with private unset"
      },
      "items": {
        "1 changeset row": "DONE in its own commit 797caf0c, taken first as triage 5692961190 directed; window re-measured on origin/main immediately before the commit",
        "2 dead dependency": "DONE in bccdf6c1b - removed and ESTABLISHED safe, see transitive_consumer_reading",
        "3 plugin-audit stale citations": "DONE in 466593dc0",
        "4 err-message site count three->two": "DONE in 466593dc0, measured not carried"
      },
      "transitive_consumer_reading": {
        "verdict": "SAFE TO REMOVE - established by reading, not assumed",
        "metadata dist occurrences of platform-objects": 0,
        "metadata dist files scanned": 30,
        "positive control - other 9 declared deps in same dist": "present in 4-12 files each",
        "workspace packages with a real platform-objects module specifier": 23,
        "of those, declaring it themselves": 23,
        "of those, resolving it transitively": 0,
        "example apps referencing it": 0,
        "standing gate": "check:undeclared-dep-imports green - enforces that non-test src/** may only import what the manifest declares",
        "declared residual": "an EXTERNAL consumer importing @objectstack/platform-objects undeclared while relying on npm flat-hoist through @objectstack/metadata loses that accidental resolution; unmeasurable from here, is the class this repo gate treats as a defect, and platform-objects publishes on its own so the supported spelling exists. The changeset states the one-line fix."
      },
      "gates": {
        "node packages/lint/scripts/check-reference-carrier-shape.mjs": 0,
        "node packages/lint/scripts/check-reference-carrier-shape.mjs --self-test": 0,
        "node scripts/check-adr-0087-registration.mjs --base origin/main": 0,
        "node scripts/check-adr-0087-registration.mjs --self-test": 0,
        "node scripts/check-changeset-fixed.mjs": 0,
        "node scripts/check-changeset-no-major.mjs --base origin/main": 0,
        "node scripts/check-changeset-no-major.mjs --self-test": 0,
        "node scripts/check-ci-filter-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs --self-test": 0,
        "node scripts/check-comment-mask-adoption.mjs": 0,
        "node scripts/check-comment-mask-adoption.mjs --self-test": 0,
        "node scripts/check-comment-mask-corpus.mjs": 0,
        "node scripts/check-empty-changeset.mjs --base origin/main": 1,
        "node scripts/check-empty-changeset.mjs --self-test": 0,
        "node scripts/check-keyed-text-bounds.mjs": 0,
        "node scripts/check-keyed-text-bounds.mjs --self-test": 0,
        "node scripts/check-osv-exemptions.mjs": 0,
        "node scripts/check-osv-exemptions.mjs --self-test": 0,
        "node scripts/check-platform-object-tenancy-census.mjs": 0,
        "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0,
        "node scripts/check-plugin-teardown-shape.mjs": 0,
        "node scripts/check-plugin-teardown-shape.mjs --self-test": 0,
        "node scripts/check-registry-log-declared.mjs": 0,
        "node scripts/check-registry-log-declared.mjs --self-test": 0,
        "node scripts/check-rest-log-spy-declared.mjs": 0,
        "node scripts/check-rest-log-spy-declared.mjs --self-test": 0,
        "node scripts/check-system-context-census.mjs": 0,
        "node scripts/check-system-context-census.mjs --self-test": 0,
        "node scripts/check-tenant-audit-census.mjs": 0,
        "node scripts/check-tenant-audit-census.mjs --self-test": 0,
        "node scripts/check-undeclared-dep-imports.mjs": 0,
        "node scripts/check-undeclared-dep-imports.mjs --self-test": 0,
        "node scripts/docs-audit/check-affected-docs.mjs": 0,
        "node scripts/docs-audit/check-drift-comment.mjs": 0,
        "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0,
        "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0,
        "pnpm --filter @objectstack/spec run check:llms-txt": 0,
        "pnpm check:changeset-gate-self-tests": 0,
        "pnpm check:cross-package-test-inputs": 1,
        "pnpm check:doc-authoring": 0,
        "pnpm check:driver-memory-census": 0,
        "pnpm check:dts-closure": 0,
        "pnpm check:dual-build-cjs-loads": 0,
        "pnpm check:durability-log-level": 0,
        "pnpm check:engine-double-contract": 0,
        "pnpm check:i18n": 0,
        "pnpm check:i18n-stale-fill": 0,
        "pnpm check:lean-entry-closure": 0,
        "pnpm check:logger-receiver-detach": 0,
        "pnpm check:manifest-repository-directory": 0,
        "pnpm check:merge-driver": 0,
        "pnpm check:nul-bytes": 0,
        "pnpm check:objectql-double-limit": 0,
        "pnpm check:objectui-changeset": 0,
        "pnpm check:org-identifier": 0,
        "pnpm check:override-consistency": 0,
        "pnpm check:page-declaration-shape": 0,
        "pnpm check:pm-changeset-deadline-census": 0,
        "pnpm check:published-files": 0,
        "pnpm check:query-options-erasure": 0,
        "pnpm check:refd-timer-probe": 0,
        "pnpm check:service-providers": 0,
        "pnpm check:slot-lookup": 0,
        "pnpm check:sourcemap-no-sources-content": 0,
        "pnpm check:test-source-alias": 0,
        "pnpm check:tier-file-adoption": 0,
        "pnpm check:turbo-task-graph": 0,
        "pnpm check:type-check-coverage": 0,
        "pnpm check:type-check-debt": 0,
        "pnpm check:type-source-resolution": 0,
        "pnpm check:vendor-export-contract-resolve": 0,
        "pnpm check:watch-hint-literal": 0,
        "pnpm check:where-matcher": 0,
        "pnpm check:workspace-manifest-cycles": 0,
        "pnpm lint": 0,
        "pnpm --filter @objectstack/metadata --filter @objectstack/plugin-audit run typecheck": 0,
        "pnpm --filter @objectstack/metadata --filter @objectstack/plugin-audit run test": 0,
        "pnpm install --frozen-lockfile": 0
      },
      "gate_summary": {
        "derived": 75,
        "run": 75,
        "green": 73,
        "not_measured": 0,
        "reconciliation": "dispatch-gates --ran with exit codes: 75 derived accounted for, 75 run, 0 NOT-MEASURED (DERIVED zero, not claimed)",
        "pnpm lint": "exit 0, full-repo union, not a narrowing, on head 466593dc0"
      },
      "tests": "pnpm --filter @objectstack/metadata --filter @objectstack/plugin-audit run test :: exit 0 (VERDICT command-exit 0 under os-verify-lock) - metadata 53 files/788 tests passed, plugin-audit 24 files/346 tests passed. typecheck :: exit 0 for both. pnpm install --frozen-lockfile :: exit 0, which is the exact CI check that was failing. Ablation for the one pre-existing red: all 7 changed tracked paths restored to BASE blob (each verified by git hash-object against BASE:path) and the added changeset removed, on this head and build state -> check:cross-package-test-inputs still exits 1; restore afterwards left git status empty.",
      "mcp_calls": "0 - no MCP GitHub tool called, read or write",
      "api_writes": "4 REST proxy writes: POST /repos/.../pulls (draft create, PR 18389); PATCH /repos/.../pulls/18389 (body, Clause-2 line); PATCH /repos/.../pulls/18389 (body, final gate numbers); POST /repos/.../issues/17281/comments (this report). Plus 4 git pushes: initial empty branch, item 1, items 2-4, and one --force-with-lease. A first POST /pulls attempt returned HTTP 415 (missing Content-Type) and created nothing.",
      "line_budget": "not applicable - zero files under skills/** in the diff",
      "deviations": [
        "check:empty-changeset exit 1 - RED BY DESIGN, DELIBERATE CORRECTION class, awaiting maintainer confirmation. Not an unfixed failure: the gate refuses any edit to a changeset present on the merge base, its own text says it stays red either way, and the remedy it names is a human confirmation. The COLLISION remedies (restore from base / rename / drop the row) would each destroy item 1.",
        "check:cross-package-test-inputs exit 1 - PRE-EXISTING, proven by ablation on this head and build state. Names @objectstack/cli descending packages/spec/dist/; neither package is in this diff. An earlier control on the shared checkout read green and was VACUOUS (empty packages/spec/dist there, so the walk had nothing to descend) - reported so the false green is not reused.",
        "MY MISS, self-reported: the first push of item 2 carried packages/metadata/package.json without a regenerated pnpm-lock.yaml, reddening every CI job at the install step with ERR_PNPM_OUTDATED_LOCKFILE. Fixed with pnpm install --lockfile-only (never hand-edited); the whole lockfile diff is the 3 lines of the one removed edge. Folded INTO the item-2 commit by history rewrite rather than appended, after verifying all five AGENTS.md force-push criteria held (claude/issue-* branch, this worktree created it, author+committer sets are me alone, PR had zero reviewers and zero reviews, --force-with-lease pinned to the sha I last pushed). Tree after the rewrite is identical to the old head except the 3 lockfile lines.",
        "SCOPE EXTENSION, declared: packages/metadata/tsconfig.json paths mapping was removed alongside the package.json and vitest.config.ts entries. The card named only two sites; this is the same dead specifier in the same package, and removing the dependency while leaving a tsconfig path resolving it would be a half-done job. Bounded in-place criteria all hold.",
        "NO LABEL WRITE. The agent rules put POST /issues/{n}/labels in the standard four-write budget; this dispatch enumerated three writes and did not include it. Followed the dispatch budget and flagging the conflict rather than choosing silently. No label-reading gate is red on the PR.",
        "PR body attribution footer is the BARE form, not the session-URL form. The REST edit path appended its own bare footer; I sent the body footer-free each time and read back exactly ONE footer after both PATCHes. Not re-sent to correct the form, because re-sending a body that already carries an appended footer is what produces two.",
        "Commit trailers: the harness Co-Authored-By naming a model was refused by the pre-push hook check:commit-card-trailers. Reworded to the model-free pair while the commit was still unpushed, as the hook prescribes. No override used."
      ],
      "files_changed": [
        ".changeset/retire-adr-0030-notification-event-migration.md (+1, item 1)",
        ".changeset/17281-metadata-drops-dead-platform-objects-dep.md (new, +39, item 2 publishes)",
        "packages/metadata/package.json (-1)",
        "packages/metadata/tsconfig.json (-5/+2)",
        "packages/metadata/vitest.config.ts (-12)",
        "pnpm-lock.yaml (-3)",
        "packages/metadata/src/migrations/raw-exec-operator-detail-16657.test.ts (+6/-1, comment only)",
        "packages/plugins/plugin-audit/src/read-audit-view-instant-preservation.integration.test.ts (+11/-5, comment only)"
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: the changeset edited for item 1 carries no line-initial Clause-2 declaration, and did not before this PR either (4 of 333 changesets carry one). Successor: the release seat that compiles this note. In PR acceptance notes.",
        "noted, not filed: packages/metadata/vitest.config.ts keeps one platform-objects mention on purpose - the @objectstack/spec namespace-rule comment contrasts spec's uniform export map with the FILE-shaped @objectstack/platform-objects/plugin subpath. Still accurate and load-bearing about spec, not residue. Successor: none; left deliberately.",
        "noted, not filed: check:cross-package-test-inputs is red on origin/main whenever packages/spec/dist is built - @objectstack/cli descends it from packages/cli/test/init-created-files-summary.e2e.test.ts with no declared glob reaching inside. Not filed by me because it is invisible on an unbuilt tree and I cannot tell from here whether a card already covers it; PM has the dedupe read. Successor: the next PR touching packages/cli test inputs."
      ]
    }

    Generated by Claude Code

  5. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    ACCEPT — PR #18389, head 466593dc0395ad6dfb11d376097147a2bcbd44aa

    domain:cli execution PM seat, session session_01DvvamiacK328idtBYJBxV3, R76, 2026-09-16T08:50Z. Reviewed against GitHub and the tree, ⛔ not against the report's own prose. ⚠️ ACCEPT is the review verdict; this PR is ⛔ NOT being flipped to ready — see the landing section.

    Checklist conclusions — each from a reading this seat took

    item reading
    PR shape draft ✅ · base main ✅ · body first line Fixes #17281 ✅ · 0 requested reviewers, 0 reviews
    scope 8 changed files pulled from the API, ⛔ not from the report — they match the report exactly
    release guardrail ⛔ no content/docs/releases/ path in the diff
    lane fence ⛔ no packages/spec/ path in the diff
    changeset @objectstack/metadata reads private unset on origin/main ⇒ published ⇒ a changeset is owed, and .changeset/17281-metadata-drops-dead-platform-objects-dep.md carries it
    required jobs on this head TypeScript Type Check success · Lint & Repo Gates success — each verified with head_sha == head.sha, ⛔ not read off an aggregate
    clause ② node scripts/pm/check-clause2-carriers.mjs --pair 18389 → exit 0: declaration readable in the fixed spelling, both carriers agree, no widening tell
    mcp_calls reported 0; ⛔ no denied-roster tool appears in the record

    The history rewrite — checked against AGENTS.md, ⛔ not accepted on assertion

    AGENTS.md:470-477 allows --force-with-lease only while all five hold. Independently verified:

    • ① branch is claude/issue-17281-adr-0030-retirement-residue ✅
    • ③ git log origin/main..origin/<branch> — all 3 commits carry author and committer Claude <noreply@anthropic.com>, one identity, ⛔ nobody else ever pushed ✅
    • ④ requested_reviewers [], requested_teams [], reviews [] ⇒ no reviewer, no approval ✅
    • ② and ⑤ are the delivering agent's own claims and are ⛔ not independently verifiable from this seat; the resulting history (3 clean commits) is consistent with them.

    ⭐ Commit trailers are model-free — Co-authored-by: Claude + Claude-Session:, ⛔ no model name — which is the required form.

    Deviations accepted, each with its reason

    1. check:empty-changeset red — BY DESIGN. Established independently by this seat before the report arrived (5694427923): DELIBERATE CORRECTION class, and the gate's source says it stays red either way. ⛔ Not a failure of this delivery.
    2. check:cross-package-test-inputs exit 1 locally — PRE-EXISTING, and ⛔ green in CI. CI on this head reads 40 success / 6 skipped, with the only reds being the changeset gate. The delivering agent's ablation is corroborated by the dedupe read below.
    3. Scope extension to packages/metadata/tsconfig.json — declared, ⛔ not silent. Same dead specifier, same package; removing the dependency while leaving a paths mapping resolving it would be half a job. Accepted.
    4. No label write. Correct: the agent rules' standard four-write budget includes a label POST, this dispatch enumerated three, and the agent followed the dispatch and flagged the conflict rather than choosing silently. ⭐ No label was owed — clause ② is no and mechanically confirmed, so ⛔ no needs:contract-review carrier applies.
    5. ⭐ A self-reported miss. The first push of item 2 carried packages/metadata/package.json with no regenerated lockfile, reddening ~20 jobs at the install step. It was reported as the agent's own error rather than described as an environment problem. ⛔ Counted as a deviation, ⛔ not as a rework: the fix used pnpm install --lockfile-only (⛔ never hand-edited) and the whole lockfile diff is the 3 lines of the one removed edge.

    out_of_scope_findings — dedupe run from this seat, which is the duty the agent could not discharge

    It declined to file its third finding (check:cross-package-test-inputs red on a built tree) because it could not dedupe from its container, and handed the read over. ⭐ That was the right call — the finding is already filed twice, both open:

    ⇒ ⛔ No new card filed — a third twin is exactly what 「立卡者不查重」 exists to prevent. The other two findings (the changeset's own missing clause-② line; the deliberate platform-objects mention kept in vitest.config.ts for a spec-namespace contrast) are ⛔ outside the three filing classes and correctly live in the PR's acceptance notes.

    ⏳ Landing — ⛔ PARKED, and the reason is not a defect in this work

    All three 「by-design red may ride into the queue」 conditions are satisfied and were each verified by reading: the gate self-describes as staying red (scripts/check-empty-changeset.mjs:599-606), it ⛔ does not run on merge_group (pr-automation.yml declares on: pull_request only), and the gate and its cause are recorded on the PR.

    ⛔ This seat is still not enqueueing it. The gate's whole purpose is to put a pending-release-note edit in front of a person, and release actions sit on the manual floor — 〈红线〉: 「⛔ 永不跑版本发布」. Enqueueing on a technicality would route around the one decision the gate exists to force.

    ⇒ Awaiting the maintainer's confirmation of item 1's row. ⏳ The clock is real: PR #17076 (chore: version packages) is open, and the moment it merges the row can never be added.

    domain:cli execution PM seat · #6024 · session session_01DvvamiacK328idtBYJBxV3 · R76 · ACCEPT · Implemented-by: branch claude/issue-17281-adr-0030-retirement-residue · Reviewed-by: session_01DvvamiacK328idtBYJBxV3 · reading time 2026-09-16T08:50Z


    Generated by Claude Code

  6. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    重新派发 — item 1 改走 B 路,卡面不变、范围不变

    维护者已就 item 1 给出裁定,记录在 PR #18389 的 5698965201(裁定原话与四项影响对照表都在那里,⛔ 此处不复述)。一句话:既有的 .changeset/retire-adr-0030-notification-event-migration.md 一个字节都不动,@objectstack/platform-objects: minor 改由一份按卡号命名的新 changeset 承载。

    ⇒ 本卡的交付面不变、验收不变、Clause-②: no 不变;变的只是 item 1 用哪份文件承载那次升级。发布结果相同:platform-objects 仍在本轮拿到 minor。

    ⭐ 这解开的是落地路径,⛔ 不只是一个红灯。 Check Changeset 是 by-design 红,而 #18404 已确认落地前检 ③ 没有 by-design 豁免 ⇒ 红着这张 PR 只能由维护者手合。B 让它走回正常队列。

    ⛔ 派发令里挂了两条必须先证伪的前提,⛔ 不是结论

    1. 还原 base 那份说明是否会 republish 一句现在为假的话 —— 本席读作「漏报,非假」(platform-objects 是在原始退役 PR refactor(metadata,spec)!: retire the adr-0030-notification-event migration — no operator door, no platform invoker #17194 里变的,本 PR ⛔ 不碰该包)。若实测相反 ⇒ 交付方立即停手上报,B 不安全,裁定退回维护者。
    2. 声明一个 diff 未触碰的包 会不会被别的闸门拒 —— 本席只读到 check-changeset-no-major.mjs:2697 关于 patch 的自测断言,⚠️ 而我们要的是 minor,必须对 minor 实跑,⛔ 不得由 patch 推。

    顺带更正本席在本卡上的一处读数

    此前报「40 绿 + 3 条 by-design 红」。重读 head 466593dc 的 49 条 check run:failure 只有 Check Changeset 一个 check,3 次是同一 check 被重触发的 3 次运行。⇒ 一条红,⛔ 不是三条。

    Dispatched and readings taken 2026-09-16T14:17Z.


    Generated by Claude Code

  7. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    os-dev-report

    {
      "issue": 17281,
      "status": "done",
      "branch": "claude/issue-17281-adr-0030-retirement-residue",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18389",
      "session": "session_01DvvamiacK328idtBYJBxV3",
      "premise_still_valid": true,
      "summary": "Executed maintainer ruling 5698965201 (route B) on the existing PR #18389, as one commit d2544585e on top of 466593dc0 — no new branch, no new PR, no history rewrite. (1) .changeset/retire-adr-0030-notification-event-migration.md restored to its merge-base blob: `git rev-parse 8b81ab60d:PATH` and `git hash-object` on the restored working-tree file both read 2ae652749b40dec974fdfb5fcf5fe0990267fe53, `git diff 8b81ab60d HEAD -- PATH` prints nothing, and the path is gone from the PR's file list entirely; `git status --porcelain` was read before committing (the checkout-from-ref staged it, which is what the commit wanted). (2) New issue-scoped changeset .changeset/17281-platform-objects-attest-fresh-datastore.md declaring exactly '@objectstack/platform-objects': minor, with a release-reader note: a datastore created from empty now attests two creation-attested migration ids instead of three, because attestFreshDatastore (packages/platform-objects/src/system/migration-flag.ts) defaults to CREATION_ATTESTED_MIGRATION_IDS and that tuple lost 'adr-0030-notification-event'. (3) PR body rewritten: the whole 'This item makes check:empty-changeset go red, by that gate's own design' section is deleted and replaced by item 1's new description plus a section naming ruling 5698965201, what B is, and the one declared cost (a separate platform-objects CHANGELOG entry rather than a row on the retirement note). The line-initial `Clause-②: no` is preserved verbatim at line 3 and verified present in the STORED body after read-back. Items 2/3/4 untouched except the one acceptance-note bullet that this change made false. No labels, no assignee, no draft flip, no auto-merge, no enqueue.",
      "premises_measured": {
        "premise_1_restoring_the_base_note_republishes_a_false_sentence": {
          "verdict": "FALSIFIED — the base note is UNDER-DECLARED, not false. B is safe.",
          "measurement": "This PR's file list vs merge base 8b81ab60d is 8 paths, all under .changeset/, packages/metadata and packages/plugins/plugin-audit, plus pnpm-lock.yaml — ZERO paths under packages/platform-objects or packages/spec. Every claim in the base note is about the retirement itself (deleted runner, its three result/option/receipt types, CREATION_ATTESTED_MIGRATION_IDS going 3 to 2, NOTIFICATION_EVENT_MIGRATION_ID kept, attestFreshDatastore no longer including the id).",
          "control_that_could_have_falsified_it": "grep -nE 'platform-objects|dependen|vitest|tsconfig|package\\.json|alias|paths' over the base note as it stands at the merge base — this PR's OWN subject matter — returns exit 1, ZERO hits. There is no sentence in that note about the dead dependency, the vitest alias, the tsconfig paths mapping or the two docblocks, so nothing in it can have been made false by this diff. Had a single hit come back I would have stopped and pushed nothing.",
          "corroboration": "PR #17194 (d64bcb6377) IS where platform-objects moved: its file list carries packages/platform-objects/src/system/migration-flag.ts, .../migration-flag.test.ts and packages/platform-objects/src/plugin.test.ts."
        },
        "premise_2_a_changeset_naming_a_package_the_diff_does_not_move_is_refused": {
          "verdict": "FALSIFIED — it is NOT refused. Measured for `minor` specifically, never inferred from the `patch` self-test assertion at check-changeset-no-major.mjs:2697.",
          "measurement": "check-changeset-no-major.mjs run on head d2544585e against a synthesised pull_request payload (GITHUB_EVENT_NAME=pull_request plus the script's own `--event` flag pointed at a payload file) carrying this PR's real `Clause-②: no`: EXIT 0, printing 'LEVEL AXIS: this PR declares clause-② `no`'. The plain local run (no payload) also exits 0 but reads NOT APPLICABLE, which is why the payload run was needed.",
          "firing_control": "Same command, same tree, payload flipped to `Clause-②: yes`: EXIT 1 — so the axis was live and capable of failing, and the exit 0 above is not a vacuous green. What the red prints is the sharper reading: the only package it lists is '@objectstack/metadata: patch', because packages/platform-objects/src/ is not in this diff. A `minor` on a package the diff does not move is invisible to that gate in BOTH directions — never refused, and never credited as discharging a clause-② `yes` either. Our PR declares `no`, so the axis stands down.",
          "level_not_adjusted": "The declared level is `minor`, exactly as the ruling specifies. No level was raised or lowered to quiet any gate."
        }
      },
      "check_empty_changeset_before_after": {
        "before_head": "466593dc0395ad6dfb11d376097147a2bcbd44aa",
        "before_exit": 1,
        "before_text": "This PR changes a changeset it did not add: .changeset/retire-adr-0030-notification-event-migration.md — present on the merge base and CHANGED by this PR",
        "after_head": "d2544585e464857c8a34878fed8861b97b7fa913",
        "after_exit": 0,
        "after_text": "No empty-frontmatter changeset introduced by this diff (2 declaring changeset(s) added). No changeset from the merge base modified or deleted by this diff (#17712)."
      },
      "new_changeset": {
        "filename": ".changeset/17281-platform-objects-attest-fresh-datastore.md",
        "declared_level": "'@objectstack/platform-objects': minor",
        "frontmatter_is_exactly_one_entry": true
      },
      "tests": "check-changeset-no-major.mjs: exit 0 (plain local run, and exit 0 again under a synthesised pull_request payload carrying the real `Clause-②: no`). Gate derivation on head d2544585e: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` gives 75 commands. All 75 run, each exit code written to disk BEFORE anything read it (redirect first, capture `$?` second, never across a pipe). Reconciled: `node scripts/pm/dispatch-gates.mjs --ran ran.list` exits 0 printing 'Run reconciliation — 75 derived, 75 run, 0 NOT-MEASURED, 0 UNRUN'. => 75 derived / 75 run / 0 NOT-MEASURED / 0 UNRUN. 74 of 75 green. The one red is `pnpm check:cross-package-test-inputs` exit 1 — pre-existing #18353/#18348, naming packages/cli/test/init-created-files-summary.e2e.test.ts descending packages/spec/dist; neither package is in this diff and NO fourth card was filed. Both of its readings were taken on this head: exit 0 on the unbuilt tree (vacuous — nothing to descend) and exit 1 once the build exists. Six gates first read exit 3 PREREQUISITE NOT MET — dts-closure, dual-build-cjs-loads, i18n, lean-entry-closure, sourcemap-no-sources-content, type-check-debt. NONE was recorded as a pass: the build they need was run through the shared lock (`scripts/pm/os-verify-lock.sh -c 'pnpm exec turbo run build --filter=!@objectstack/docs --concurrency=2'`, slot issue-17281-dev, waited 191s in the queue behind two sibling agents, VERDICT command-exit 0, 73 tasks / 72 cached) and all six then exit 0. `pnpm lint` — the repo-wide union (`eslint . --no-inline-config`), the standing blind spot the derivation never names — exit 0 on d2544585e, run after the final commit. STALE-TREE warning on the derivation (branch at least 31 commits behind origin/main; 10 family-defining files moved across that range) DISCHARGED BY MEASUREMENT, not by argument: a throwaway worktree checked out at origin/main 8fe5cb8e5 with this branch merged in uncommitted derives the same 8 paths and a BYTE-IDENTICAL 75-command list (`diff` exit 0); that probe worktree was then merge-aborted and removed. No ablation was owed: this commit adds no gate and no assertion — it moves two changeset files. The restoration was proven by blob identity (`git hash-object` equal to `git rev-parse BASE:PATH`), never by an exit code.",
      "mcp_calls": "0 — no MCP GitHub tool was called at all, read or write.",
      "api_writes": "2 REST-proxy writes. [1] PATCH /repos/objectstack-ai/objectstack/pulls/18389 (body only; read back immediately with a fresh GET — the stored body is a byte-identical prefix of what was sent plus exactly one 58-byte platform bare footer, one footer total, line-initial `Clause-②: no` confirmed present in the STORED body, no HTML comment, and no angle-bracket fragment anywhere in the body). [2] POST /repos/objectstack-ai/objectstack/issues/17281/comments (this report). Plus one `git push` of d2544585e (no force, no amend, no rebase; the pre-push hook printed 'check:commit-card-trailers: 1 commit message(s) on this push carry no card relation and no model identifier in the trailer pair'). ZERO label writes, ZERO assignee writes, no draft flip, no auto-merge arming, no enqueue, no POST /issues.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: the PR body's item 2 cites commit `063efde2` and items 3/4 cite `fd28ee6f`, and NEITHER is an ancestor of the branch head — `git merge-base --is-ancestor` exits 1 for both on a non-shallow repo, with a control leg (8b81ab60d) exiting 0 in the same checkout, so the negative is real and not a shallow-clone artefact. The live commits for that work are `bccdf6c1b` and `466593dc0`; the branch was evidently re-cut after that body text was written. Left untouched because the dispatch fences items 2/3/4's sections off except where MY change makes them false, and this was already false before I arrived. Picked up by: the PM seat landing #18389 — a one-word correction in two places whenever the body is next edited.",
        "noted, not filed: the behaviour delta this new changeset declares for @objectstack/platform-objects is sourced entirely from packages/spec — PR #17194's change to packages/platform-objects/src/system/migration-flag.ts is COMMENT-ONLY (one docblock paragraph rewritten; the other two platform-objects files it touched are tests). attestFreshDatastore's observable behaviour moved because its default argument is CREATION_ATTESTED_MIGRATION_IDS from @objectstack/spec/system, which went from three members to two. The minor is still correct and still owed — it is platform-objects' own exported function whose behaviour changed — but the PM's premise-1 wording ('platform-objects, which changed in the original retirement') holds at the file-list grain and NOT at the source grain, and anyone re-deriving this should know which. Picked up by: nobody in this batch; it is a note about how the declaration is justified, not a defect.",
        "noted, not filed (already filed, do not duplicate): `pnpm check:cross-package-test-inputs` exit 1 on any tree where packages/spec/dist is built, naming packages/cli/test/init-created-files-summary.e2e.test.ts — #18353 / #18348, explicitly NOT this PR's and explicitly not to be re-filed."
      ]
    }

    Generated by Claude Code

  8. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    ACCEPT — 裁定 B 已交付并实测成立;⛔ 每一条都对着 GitHub 验,不对着报告的散文

    domain:cli 执行 PM 席(#6024),R76。审的 head:d2544585e464857c8a34878fed8861b97b7fa913。

    ⭐ 决定性的一条,是内容而不是措辞

    .changeset/retire-adr-0030-notification-event-migration.md 已完全不在本 PR 的改动文件清单里。⇒ 不在 diff 里就是没碰,这比任何「已按字节还原」的说法都硬,而且它是我从 GitHub 的 file list 独立读到的,⛔ 不是从报告里抄的。

    本 PR 现有 8 个文件:两份新增的按卡号命名 changeset(17281-platform-objects-attest-fresh-datastore.md 声明 '@objectstack/platform-objects': minor,17281-metadata-drops-dead-platform-objects-dep.md 声明 '@objectstack/metadata': patch)、item 2 的四个文件、items 3/4 的两处 docblock。

    落地前检三条,逐条实测

    检 命令 读数
    ① 条款② 本卡 Clause-②: no(分诊 5692961190 与正文行首均如此),⇒ ⛔ 不欠达档复核 —
    ② 双载体 check-clause2-carriers.mjs --pair 18389 exit 0 — 「declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell」
    ③ 全绿 当前 head 的全部 check run 49 run · 0 failing · 0 pending · mergeable_state: clean
    附 check-governed-merges.mjs --test 跑最终文件清单 exit 0 — 8 条路径 0 命中受管 register ⇒ 普通队列落地

    ⭐ check:empty-changeset 由 exit 1 翻成 exit 0,这正是 B 要买的东西:466593dc0 上它印「changes a changeset it did not add」,d2544585e 上它印「No changeset from the merge base modified or deleted by this diff (#17712)」。

    ⚠️ 顺序说明,因为它差点被我做反:我在翻 ready 之前改了 PR 正文(见下),而正文编辑会重触发 Check Changeset。所以上面的「全绿」是编辑之后重新取的读数,⛔ 不是编辑之前那次。清标/改正文 → 重读全绿 → 翻 ready,三步,⛔ 永远不是两步。

    ⛔ 本席公开过的一处断言被实测推翻,在此更正,⛔ 不抹掉

    裁定记录 5698965201 里我写:「platform-objects … 是在原始退役 PR #17194 里变的」。交付方在越界发现里指出这话的粒度不对,我验了,它对:

    d64bcb6377 对 packages/platform-objects/src/system/migration-flag.ts 的整段 diff 逐行以 * 开头,全部落在 /** */ 内 ⇒ 注释级。该包源码行为不是在那次退役里变的;行为差来自 @objectstack/spec 的 CREATION_ATTESTED_MIGRATION_IDS 由三成员降为两成员。

    ⇒ 我那句在文件清单粒度成立、在源码粒度不成立。⚠️ 结论不变,且理由更硬:minor 仍然欠着,因为变的是 attestFreshDatastore —— platform-objects 自己导出的函数 —— 的可观察行为(新建库 attest 两个 id 而非三个)。包的行为经由一个 spec 常量而改变,它仍然是这个包的行为,调用方看得见。裁定 B 不受影响。

    ⭐ 这是本轮第四次「结论对、前提错」,病根同一个:先发布,后测量。

    ⚠️ PR 正文引了两个死 sha,已修,且留痕

    正文的 item 2 引 063efde2、items 3/4 引 fd28ee6f,而 git merge-base --is-ancestor 判定两者都不是本分支 head 的祖先(控制腿:merge base 8b81ab60d 在同一 checkout 里 exit 0 ⇒ 判据是活的,负读数为真)。分支在那段正文写好之后被重切过。实测归属:bccdf6c1b = item 2(依赖 + lockfile),466593dc0 = items 3/4(两处 docblock)。

    ⛔ 没有静默替换:正文里留了一句写明曾经引错、判据是什么、控制腿是谁,这样记录本身能自证。

    越界发现的跨批次去重 —— 本报告 0 新卡,逐条给理由

    1. 死 sha — ⛔ 不立卡,已在本轮当场修掉。
    2. 源码粒度那条 — ⛔ 不立卡:它是「这条声明凭什么成立」的注记,⛔ 不是缺陷;minor 经复核仍然正确。已并入上面的更正。
    3. check:cross-package-test-inputs — ⛔ 不立卡,已存在 [finding] check:cross-package-test-inputs passes in CI and fails on a built tree — its verdict is a function of gitignored build state #18353 / [regression] check:cross-package-test-inputs 的裁决取决于被 gitignore 的空目录 packages/spec/dist 存不存在 —— 构建过的工作树一律红,CI 绿只因那一步跑在构建之前(#18340 引入) #18348。⚠️ 本批三个 dev 会各自撞到它;跨批次去重是本席的活,dev 看不见彼此。

    残留,声明而非隐藏

    ⚠️ 外部消费者若安装 @objectstack/metadata、未声明却 import @objectstack/platform-objects、并依赖 npm 扁平提升,会失去那次偶然解析。此处不可测;它也正是本仓自有闸门视为缺陷的那一类,且 platform-objects 自行发布,受支持的写法存在。changeset 里写了那一行修法。

    ⇒ ACCEPT。 转 ready,挂 auto-merge,入队。落地后按 origin/main 的内容验,⛔ 不凭合并事件。

    Reviewed against GitHub and posted 2026-09-16T14:57Z.


    Generated by Claude Code

  9. removed their assignment
    on Sep 16, 2026
  10. os-support-ai commented on Sep 16, 2026

    @os-support-ai
    Collaborator

    落地记录 — b6471ba1fc12d372d69cf523da137a5482facb9e,按 origin/main 的内容验,⛔ 不凭合并事件

    裁定 5698965201(路线 B)已端到端交付。⛔ 一个读数都不是从 PR 正文或交付报告里抄的。

    检 命令面 读数
    ① 结构 git rev-list --parents -n 1 2 字段 ⇒ squash 落地,单亲
    ② 在 main 上 merge-base --is-ancestor b6471ba1 是 origin/main 的祖先
    ② 负控制 同命令,喂 squash 前的 head d2544585e 不是祖先 ⇒ ⭐ 这个判据能失败,所以 ① 的通过是读数而非恒真
    ③ B 的交付物 git show origin/main:.changeset/17281-platform-objects-attest-fresh-datastore.md 存在,声明 '@objectstack/platform-objects': minor
    ③ 那份既有说明 git rev-parse origin/main:.changeset/retire-adr-0030-notification-event-migration.md blob = 2ae652749b40dec974fdfb5fcf5fe0990267fe53,与 merge-base blob 逐字节相同 ⇒ ⛔ 一个字节未动
    ③ item 2 packages/metadata/package.json 的 platform-objects 0 命中;控制 @objectstack/spec 1 命中 ⇒ grep 是活的,零是读数

    ⏳ 时钟赢了

    item 1 的整个不可逆风险是:PR #17076(chore: version packages)一旦合并,那一行就永久丢失。它在本卡落地时仍 open / merged: false。⇒ 那一行已入账,platform-objects 会在本轮发布里拿到 minor。

    ⭐ B 买到的是什么,用闸门自己的话

    466593dc0 上 check:empty-changeset 印:

    This PR changes a changeset it did not add: .changeset/retire-adr-0030-notification-event-migration.md — present on the merge base and CHANGED by this PR

    d2544585e 上它印:

    ✓ No changeset from the merge base modified or deleted by this diff (#17712).

    ⇒ 那条 by-design 红 ⛔ 没有被标签压住、⛔ 没有被绕过、⛔ 没有被人手合过去——它消失了,因为 PR 不再做闸门禁止的那件事。落地前检三条(席内条款②、双载体 --pair exit 0、全部 check 全绿)在改完正文之后重取,全部通过;check-governed-merges --test 对最终 8 条路径 exit 0。

    残留已清并回读

    pm:dispatched 与 assignee os-support-ai 由本席手工剥除(Fixes 关卡但不清残留),回读:labels priority:p2 · domain:cli,assignees 无。

    四项交付,逐项落地

    item 1 换更集行(改由新文件承载,裁定 B)· item 2 死依赖 + vitest 别名 + tsconfig paths + lockfile · items 3/4 两处过期散文。

    Landing verified and recorded 2026-09-16T15:26Z.


    Generated by Claude Code

  11. added a commit that references this issue on Sep 17, 2026
    b6471ba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpriority:p2Medium: important, M3

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions