Repository navigation
Description
domain:spec#2 · sunhaolin · session_017xRBcSbLCxEmyHf9upz3pz
Filing gate: ① a named blind spot with a measured reach, item 2 of #32345 (whose Ask says "Name the decision; changing the gate is optional and may be a separate card"). ⛔ Not a claim. Triage sets the lane and grade.
Reader: domain:spec, scripts/check-adr-0087-registration.mjs (readDisposition and the not-required categories; signal (5) in breakingDeclaration).
Dedupe: search is:issue no-migration-prescription (open and closed), is:issue adr-0087 narrowed and is:issue check-adr-0087-registration prose → no card on this; #32345 itself, and closed #22915 / #22918 / #26220 are other categories.
reach: named producers. .changeset/31224-flow-node-unreachable.md and .changeset/32289-flow-start-node-missing.md (both runtime-gate narrowings), and #32075's changeset (the G1 namespace runs refusal, seat-4 note 6797576404 on #32345), each passed this gate with not-required (no-migration-prescription) while prescribing the fix in prose. Measured by the #32345 dev (report 6817344535, with the gate's own exported readers over 1096 changesets): 39 of the 62 changesets declaring narrowed in stock carry that marker and no entry.
Business reason
An agent or author upgrading reads the ADR-0087 upgrade guide and os migrate meta to learn what the new release refuses before the save door answers 422. A narrowing is by definition a refusal of something an author used to write (ruling A, signal (5)), yet the gate lets it opt out of the guide whenever its fix is written as a sentence instead of an arrow or a framed table. Careful prose is exactly what defeats the detector, so the exemption is reachable by wording.
Seat decision (option A of the dev's three, the seat's call under the non-escalation class "an existing gate's blind-spot repair: strengthening, not weakening, not new")
When a changeset declares Metadata-protocol: narrowed (signal (5), read by the imported reader), not-required (no-migration-prescription) is refused; registered and the fact-checked categories (unpublished, already-registered, runtime-interface-only, type-surface-only) stay open. The gate judges only added or newly breaking changesets, so nothing in stock turns red.
Rejected: B (widen the prose detector): no measured candidate catches all three bodies without an arm that hits 61 of 191 stock markers, 41 on non-narrowed changesets. C (no change): leaves the opt-out reachable by wording; scope-minimal, recorded as the alternative.
Ask
- Implement A in
scripts/check-adr-0087-registration.mjs, with self-test pins: anarrowedchangeset withno-migration-prescriptionis refused; the same body withregisteredpasses; anone/added/semanticchangeset withno-migration-prescriptionstill passes. - The refusal text names the fix: register an entry under
packages/spec/src/migrations/entries/semantic/. - Maintainer veto window: this adds about one D3 entry per narrowing PR.
Activity
objectstack-fleet commentedon Nov 12, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch →
domain:spec·tooling· p2 ·pm:queue· 2026-11-12T07:47Z⛔ Not a claim.
domain:spec(scripts/check-adr-0087-registration.mjs; a gate script, spec by the anchoring rule).narrowedpassed withnot-required (no-migration-prescription)and no entry.Generated by Claude Code
objectstack-fleet commentedon Nov 12, 2026
domain:spec#2 · sunhaolin · session_017xRBcSbLCxEmyHf9upz3pz
Claim: PM loop round 1
Session:
session_017xRBcSbLCxEmyHf9upz3pzAccount:
sunhaolinBranch:
claude/issue-32601-narrowed-no-prescription-refusedWorktree:
objectstack-issue-32601Domain:
domain:specSeat:
domain:spec#2File surface:
scripts/check-adr-0087-registration.mjs(readDisposition/ thenot-requiredcategories, beside signal (5)), its self-test block, a changeset if the repo's changeset gate wants one for a script-only change (stop on breach; explain in the report)Container & model:
S/M,mode:subagent,model: opus (TIER_DEFAULT; --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the platform's own changeset gate (objectstack, scripts/check-adr-0087-registration.mjs) | none: the prose detector misses careful prose | every PR declaring Metadata-protocol: narrowed; 39 of 62 narrowed changesets in stock carry the opt-outThread-read: 6817901729
Premise: holds (measured by the #32345 dev, report 6817344535, with the gate's own exported readers; the seat decision is in the card body)
Serial constraints cleared:
none — no open PR touches check-adr-0087-registration.mjsobjectstack-fleet commentedon Nov 12, 2026
domain:spec#2 · sunhaolin · session_017xRBcSbLCxEmyHf9upz3pz
os-dev-report
{ "issue": 32601, "status": "done", "branch": "claude/issue-32601-narrowed-no-prescription-refused", "pr": "https://github.com/objectstack-ai/objectstack/pull/32649", "session": "session_017xRBcSbLCxEmyHf9upz3pz", "premise_still_valid": true, "summary": "Implemented seat decision A in scripts/check-adr-0087-registration.mjs. scan() now refuses `not-required (no-migration-prescription)` on any changeset whose breakingDeclaration().signals carry NARROWED_SIGNAL. That signal is a declared `Metadata-protocol: narrowed`, read only through the imported readMetadataProtocolLine; there is no second parser. The refusal is judged right after the closed-vocabulary check and before the 40-character justification check. Its text names the fix: register an entry under packages/spec/src/migrations/entries/semantic/ (precedent 18.picklist-binding-unknown-refused.ts), or use a fact-checked category if one is true. Stays open on a narrowing: registered, already-registered, unpublished, runtime-interface-only, type-surface-only and runtime-export-retired. Keep the catch-all: added, semantic and none. A malformed kind line triggers nothing, and inherited stock is never re-judged. The --audit-stock classifier (classifyStockChangeset) now reports an unanswered narrowing as residue instead of exempt-no-prescription, so it agrees with the gate. A header section documents the rule. Mechanism assumptions confirmed: readDisposition parses the marker, and a narrowed-only changeset (minor bump, no banner, no !, no arm) reaches the category dispatch as breaking by signal (5) alone; NP-0 pins that. Ruling note: the ruling's list of open categories leaves out runtime-export-retired, which is also fact-checked. The ruling refuses exactly one category, so runtime-export-retired stays open.", "tests": "head f8e7263f. node scripts/check-adr-0087-registration.mjs --self-test: exit 0, '✓ check-adr-0087-registration --self-test: 739 assertions over real temp git repos (real scan()/assertInputs() path)'. New battery 'NP (#32601): a declared narrowing cannot hold the catch-all', floor 29: NP-0 (signal 5 alone); NP-R1/R2 refused, both with signal 5 alone and with arm + banner; NP-R3 narrowing refusal ordered before the length check; NP-G1 same body registered passes; NP-G2 already-registered passes; NP-G3 added/semantic/none + catch-all pass and are asserted JUDGED, not skipped; NP-G4 malformed kind line passes and is judged; NP-G5 inherited stock is skipped; NP-S1/S2 stock classifier. pnpm check:changeset-gate-self-tests: exit 0 (167 / 739 / 456 assertions). Real-input before/after: I put PR #32611's added changeset on a throwaway commit object over this head and judged it through the CLI with --base origin/main --head SHA. Base script 8bfbc4ed: exit 0, '✓ ... 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition'. This branch: exit 1, '✗ check-adr-0087-registration: 1 problem(s)' with the new refusal. No ablation: the dispatch's 'Ablate once' conflicts with os-dev ('配置、脚本、workflow、文档 ⛔ 不消融'), and os-dev wins. The real-input before/after stands in for it. Stock measurement on 8bfbc4ed, using the gate's exported parseChangeset/breakingDeclaration/readDisposition over 1101 pending changesets: 243 breaking, 63 narrowed. Of the 63: 40 no-migration-prescription, 20 registered, 3 already-registered, 0 unmarked. Newly failing on this PR's diff: 0 (`--base origin/main`: 'this PR adds no declared-breaking changeset').", "gates": "Local subset, all on head f8e7263f, each exit captured before any pipe; every one of these exited 0: pnpm check:agent-test-spelling, bash32-floor, changeset-gate-self-tests, ci-filter-parity, cli-command-ids, cross-package-test-inputs, driver-memory-census, entry-guard, gitlink-declared, nul-bytes, parse-guard, pnpm-filter-targets, pnpm-flag-spellings, ratchet-remedy-authority, refd-timer-probe, scripts-symbol-anchors, watch-hint-literal; node scripts/check-adr-0087-registration.mjs --base origin/main and --self-test; check-declaration-mirrors, check-self-test-wired, check-self-test-workflow-commands, check-whole-set-label-write, check-closing-keyword-parity (each + --self-test); check-comment-mask-corpus; ci/plan-test-core-shards --self-test; pm/bare-root-worklist --self-test. pnpm check:pm-dispatch-gates ran detached (it exceeds the foreground cap) and its exit code was NOT captured. Its own verdict line: '✓ dispatch-gates self-test (fast tier): 2205 cases pass; 9 slow section(s) deferred.' My derivation (node scripts/pm/dispatch-gates.mjs --commands on f8e7263f) named 33 families, 9 beyond the seat's list derived on 0f9b5653; all were run. Reconciliation: node scripts/pm/dispatch-gates.mjs --ran: exit 0, '✓ 33 derived famil(ies) accounted for — 33 run, 0 NOT-MEASURED (… 1 of 33 recorded no exit code)'. CI check-runs on PR #32649: in_progress at report time; not waited on.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no MCP GitHub calls", "api_writes": "2 — relay strokes via POST /repos/objectstack-ai/objectstack/dispatches: (1) pr_create, which executed the draft create of #32649 plus POST issues/32649/assignees (sunhaolin) and POST issues/32649/labels (skip-changeset); (2) this os-dev-report comment on #32601 via post-stamped.mjs. git push (×2) is not a REST write.", "line_budget": "n/a — no skills/** or ratcheted ledger touched", "files_changed": ["scripts/check-adr-0087-registration.mjs (+188 / -4)"], "deviations": [ "No ablation, though the dispatch's suggested route asked for one: os-dev says scripts are not ablated, and os-dev wins. The real-input before/after (base green, head red on PR #32611's changeset) stands in for it.", "pnpm check:pm-dispatch-gates ran detached without an exit-code wrapper. Only its verdict line is evidence.", "Open-PR check bounded to the three lane PRs the dispatch named (#32611, #32625, #32597). No board sweep." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: PR #32611 · its added changeset .changeset/32503-object-grid-column-summary-refused.md declares Metadata-protocol: narrowed and holds not-required (no-migration-prescription). Whichever of #32611 / #32649 lands second goes red on the other's terms: if #32649 lands first, #32611 needs a semantic entry plus `registered`. Not edited; noted, not filed.", "carrier: domain:spec seat · ADR-0087's prose for `no-migration-prescription` does not yet say it is refused on a declared narrowing. That is a governed surface (docs/adr/**), so I left it out of this PR. The CATEGORIES vocabulary is unchanged, so assertInputs' ADR/CATEGORIES set check is unaffected. Noted, not filed." ] }objectstack-fleet commentedon Nov 12, 2026
domain:spec#2 · sunhaolin · session_017xRBcSbLCxEmyHf9upz3pz
ACCEPT → PR #32649 comment 6819769601 · head
f8e7263f· readied and armed for the merge queue at 2026-11-12T09:23Z; the seat follows it to MERGED, then files the ADR-0087 prose card (domain:skills).objectstack-fleet commentedon Nov 12, 2026
domain:spec#2 · sunhaolin · session_017xRBcSbLCxEmyHf9upz3pz
Landed 2026-11-12T09:43Z: PR #32649 merged as
a8c761fb(merged_at 2026-11-12T09:42:31Z).GET /pulls/32649merged: true, merge commita8c761fbe5ec06978f5e3582a35cf8be0c0503aegit log -1 origin/main -- scripts/check-adr-0087-registration.mjsa8c761fb(#32649)State: the card is closed
completedbyFixes #32601;pm:dispatchedis removed in this stroke. Delivered: seat decision A —not-required (no-migration-prescription)is refused on a changeset declaringMetadata-protocol: narrowed. Left: ADR-0087's prose does not say so yet; the governed-text follow-up is filed as its owndomain:skillscard (the ACCEPT'scarrier:line).