skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill - #14777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites
Sep 3, 2026
Merged

skills(data): drop the two bare ADR-0010 citations from the objectstack-data skill#14777
os-zhuang merged 1 commit into
mainfrom
claude/issue-11791-adr-0010-bare-sites

Conversation

@os-litant

@os-litantos-litant commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes#11791

skills/objectstack-data/SKILL.md carried bare ADR-0010 citations. 0010 is claimed by two unrelated records — 0010-metadata-protection-model and 0010-nl-to-flow-authoring, frozen in check-adr-anchors.mjs's shrink-only KNOWN_NUMBER_COLLISIONS — and the published catalog ships into codebases with no docs/adr/ to grep, so neither site resolved for its actual audience.

Scope is the ADR-0010 sites in skills/objectstack-data/** and nothing else. The catalog-wide convention question (whether published skills keep provenance ids at all) belongs to #11052 and is deliberately not settled here.

Sites

Line numbers are measured on origin/main at 224f8ea4 (the branch base), which is where the "before" column is read.

1 · authored reason: string — SKILL.md:611 before / :610 after

The sharpest of the two: reason is not documentation about the platform, it is authored metadata that ships in the customer's own code. An authoring agent following this example writes see ADR-0010 into customer metadata, somewhere no later pass over this repo can reach. The correct form was already sitting on the next line — a docsUrl pointing at a public page that resolves.

before reason: 'Core identity object — see ADR-0010.',
after reason: 'Core identity object',

docsUrl: 'https://objectstack.ai/docs/references/shared/protection' on the following line is untouched, and so is the rest of the reason text. The block sits inside a marked os:check example, so it is type-checked; reason stays a non-empty string, which is what the .strict() schema requires (min 1 / max 500 chars).

2 · prose — SKILL.md:567 before / deleted after

 Package authors can lock shipped metadata against Studio edits / overlays / deletes.
-See ADR-0010 for the full model.

Judged in the form PR #11790 used for ADR-0057: name the record so it resolves for a reader with no docs/adr/, or drop the sentence when the surrounding text already names the model. The second branch applies here — the section heading is literally ## Metadata Protection and the sentence immediately before names the model in full ("lock shipped metadata against Studio edits / overlays / deletes"). Qualifying the number in place would have restated the heading and been additive against a ceiling with zero headroom; the citation's only unique content was a pointer the reader cannot open, and the section's own schema, lock table and enforcement paragraph follow immediately.

ADR-0019 — examined and kept

The card named five sites. Re-measured on this branch, three survive, and none is touched:

sitetoday's linethe text that selects the record
skills/objectstack-automation/SKILL.md:410"do something when the state changes" is a record-triggered Flow (ADR-0019)
skills/objectstack-automation/SKILL.md:424under the heading ### Approvals (Flow Nodes): "Since ADR-0019 there is no standalone approval-process type"
skills/objectstack-platform/SKILL.md:83"an approval is authored as a flow with Approval nodes (ADR-0019)"

The pair is 0019-approval-as-flow-node vs 0019-app-as-consumer-unit, and context selects the record at every one. Recorded here so a later sweep does not "correct" them.

The generator-owned skills/*/references/_index.md mentions are also untouched: they are generated, and they are self-disambiguating already (Metadata Protection Model — Phase 1 (ADR-0010)).

Token readings

scripts/check-skills-token-ratchet.mjs is shrink-only and both files this skill package could have been paid from sat at exactly zero headroom, so the edit is paid for inside the edited file. No ceiling is changed and nothing is re-wrapped; both edits are deletions.

Counting convention is the gate's own: ceil(utf8 bytes / 4).

fileceilingtokens beforetokens afterdelta
skills/objectstack-data/SKILL.md10009100099996−13
skills/objectstack-data/rules/security.md2480248024800 (untouched)

Gate verdict lines, quoted:

✓ check-skills-token-ratchet: skills/objectstack-data/SKILL.md is 9996 tokens (ceiling 10009; headroom 13).
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2480 tokens (ceiling 2480; headroom 0).

Published-surface size readings

Required for any diff touching skills/**. Lines are the unit; tokens reported alongside because the sibling gate prices this surface in tokens.

scopelines before → aftertokens before → afterbytes before → after
skills/objectstack-data/SKILL.md (edited file)851 → 850 (−1)10009 → 9996 (−13)40034 → 39983 (−51)
skills/objectstack-data/** (whole skill package)3727 → 3726 (−1)38150 → 38137 (−13)152599 → 152548 (−51)
all published SKILL.md (catalog)6862 → 6861 (−1)79737 → 79725 (−12)318948 → 318897 (−51)

Every reading is negative in every unit. Nothing is added anywhere.

Gates

All run under scripts/pm/os-verify-lock.sh, each exit code captured by redirect before any pipe, each gate's own verdict line quoted. Union re-derived after the last edit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at bf410c1a — the same commit every reading below was taken on.

gateexitits own verdict line
node scripts/check-skills-token-ratchet.mjs0✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.
node scripts/check-skills-token-ratchet.mjs --self-test0✓ check-skills-token-ratchet self-test: 64 cases pass.
pnpm check:skill-identifier-liveness0check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).
pnpm --filter @objectstack/spec run check:skill-examples0✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them
pnpm --filter @objectstack/spec run check:skill-docs0✅ Skill docs in sync
pnpm check:role-word0check-role-word: OK, no new occurrences of the reserved word.
pnpm check:published-readme-links0✓ check:published-readme-links — 176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s), 27 docs-site page(s) resolved (0 via redirect), 1 anchor(s) verified, 103/103 relative target(s) found in the tree.
pnpm check:nul-bytes0check-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).
node scripts/check-ci-filter-parity.mjs0OK: all 130 declared cross-package glob(s) (92 unique) are covered by core or crosspkg …
node scripts/check-cross-package-test-inputs.mjs0OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
pnpm check:cross-package-test-inputs0same verdict line as above
node scripts/check-shard-attestation.mjs0✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).
node scripts/check-test-completeness.mjs3NOT MEASURED — see below
pnpm --filter @objectstack/lint run check:doc-formula-expressions0✓ check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files …
pnpm check:agent-test-spelling0✓ check-agent-test-spelling: 0 violations — 430 file(s) · 5686 bare double-dash token(s) · 1382 launcher-rooted run(s) · 9 separator(s) JUDGED …
pnpm check:corpus-claim-drift0check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.
pnpm check:doc-authoring0✓ doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean — no internal issue-id references …
pnpm check:pm-governed-merges0✓ check-governed-merges --self-test: 243 assertions …
pnpm check:skill-compatibility0✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages
pnpm check:skill-frame-sync0✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files

check-test-completeness exit 3 is NOT MEASURED, in the gate's own words, not a red:

⚠ Arrived here from the gate family `scripts/pm/dispatch-gates.mjs` derives?
That list names this script with NO argument, which is this branch. There is no
local log to hand it, so the local reading for this gate is NOT MEASURED.
⛔ It is not a red, and there is nothing here to fix.

check:skill-examples first refused with a build prerequisite (packages/client-react/dist holds no .d.ts declarations) — the gate's own false-green refusal, exit 1 with no verdict on any surface. It was satisfied by building rather than reported as unmeasured: pnpm --workspace-concurrency=2 --filter '@objectstack/client-react...' --filter '@objectstack/client...' build, after which the gate ran to a real green. The reading above is that second, measured run.

Fence census across the edit, as an independent check that no marked block moved: the os:check marker count in SKILL.md is 5 before and 5 after, and the fence-line count is 24 before and 24 after.

Premise checks

Four premise checks on what the dispatch and the card stated. None changes the disposition; the first three change a count.

  1. Four sites were expected; two exist. The card measured four (:855:897:915:936), the unlock scan re-measured four (:861:903:921:942), and the dispatch expected four. Today git grep -n "ADR-0010" -- skills/objectstack-data returns two in SKILL.md plus the two generator-owned references/_index.md mentions. Cause, measured: commit 940c1289 (PR skills(data): optimization flight — hooks consolidated, generic patterns cut, sharingModel/Field.* /storage.notNull taught (net −9,044 tokens) #14427, "optimization flight … net −9,044 tokens", 2026-09-02) deleted the sys_role and app/setup protection examples wholesale, taking their reason: '… — see ADR-0010.' strings with them. git grep -c ADR-0010 940c1289^ -- skills/objectstack-data/SKILL.md = 4; at 940c1289 = 2. So one reason: site remained to repair, not three.
  2. Five ADR-0019 sites were expected; three exist. The card and the dispatch both name five (automation:278,289,436,806 and platform:187). git grep -n "ADR-0019" -- skills/ returns three today, at automation:410, automation:424 and platform:83. The verdict is unchanged — every survivor still sits in text that selects 0019-approval-as-flow-node, quoted in the table above — but the count and the line numbers in the card are stale, the same way the ADR-0010 ones were.
  3. The remaining ADR-0010 sites are not in rules/security.md. The dispatch suggested skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 #14673's split may have moved them there. It did not: rules/security.md carries no ADR-0010 at all, and the split (446117fc) left the ADR-0010 count in SKILL.md unchanged at 2 on both sides.
  4. The dispatch's ADR-0010 line numbers held.:567 (prose) and :611 (reason:) are correct at 224f8ea4; it is the card's and the unlock scan's numbers that are stale.

Two notes on the gate list rather than on the card: the derived union names eleven gates the dispatch did not (all run above, all green), and the dispatch named three that the union does not derive (check:skill-examples, check:published-readme-links, check:nul-bytes) — run anyway.

Governed surface

skills/** is a governed surface (Prime Directive #14). This PR is a draft and stays one: no merge, no queue, no auto-merge, no ready flip from any agent seat. skip-changeset is applied — this diff publishes nothing from any package, matching the precedent of the two most recent skills-only landings (940c1289, 446117fc), neither of which carried a changeset. No needs:contract-review: this is provenance text, and it makes no contract claim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1

…13 tokens)
`skills/objectstack-data/SKILL.md` carried two bare `ADR-0010` citations. The
number is claimed by two unrelated records (`0010-metadata-protection-model`
and `0010-nl-to-flow-authoring`, frozen in `check-adr-anchors.mjs`'s
`KNOWN_NUMBER_COLLISIONS`), and the published catalog ships into codebases with
no `docs/adr/` to grep, so neither site resolved for its actual audience.
- The `reason:` string in the `sys_user` protection example is authored
metadata that ships in a customer's own code, where no later pass over this
repo can reach it. It drops `— see ADR-0010.`; the rest of the reason and
the adjacent `docsUrl` — a public page that does resolve — both stay.
- The prose sentence `See ADR-0010 for the full model.` is dropped: the
section heading (`Metadata Protection`) and the sentence before it already
name the model, so the citation's only unique content was a pointer the
reader cannot open.
Both edits are deletions, so the shrink-only token ratchet is satisfied inside
the file: 10009 -> 9996 against a 10009 ceiling. The five `ADR-0019` sites and
the generator-owned `references/_index.md` mentions were examined and left
untouched — context selects the record at all of them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
@os-zhuang
os-zhuang marked this pull request as ready for review September 3, 2026 02:32
@os-zhuang
os-zhuang added this pull request to the merge queueSep 3, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33709251817 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 45 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33710777465 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL integration test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
    ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1800
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 50 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude