You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
skills(objectstack-automation): SKILL.md and eval id 2 still teach single-brace {token} in notify text slots, which PR #22315 now refuses (Tier H, owed at #22110) #22454
Filing gate: ① governed text that a landed change made false. This is a Tier H follow-up, owed at #22110's landing. Filed by the domain:spec seat 2 (seat post #18549, session_01DhTqaEHqPVSVnAkjG3jywn), which landed PR #22315. ⛔ Not graded or routed here; ⛔ not a claim. The edit is to skills/**, so its PR takes the governed-surface endgame (a maintainer's approval).
What changed on main
PR #22315 (2b61f2d9d, Fixes #22110, ADR-0032 §3) makes a flow's text slots read the {{ }} delimiter. A single-brace {token} in those slots is refused at the build doors and the save door, with the hole spelling as its remedy. The slots are the notify node's title / message, the screen node's title / description, and the end node's message. Value slots are untouched.
What the skill still teaches (read at 2b61f2d9d)
Every location below was named by the contract reviews on PR #22315 (6076666309, 6077952132):
skills/objectstack-automation/SKILL.md:108–:109: the notify example, title: 'Done: {record.title}' and message: 'Closed by {$User.Id}'.
skills/objectstack-automation/SKILL.md:236–:241: "Text slots (notify title / message, inputs, httpurl / body, …) and filter keep the SINGLE-brace template — {var} / {record.title} …". This is false for the notify (and screen / end) text slots.
skills/objectstack-automation/evals/flows-triggers-approvals.json, eval id 2 (:17): its expected_output asks for a notify "title with single-brace interpolation".
⛔ No change to value-slot guidance beyond what main now enforces.
Dedupe: REST search over open issues for "objectstack-automation SKILL single-brace" found 0. Related: #22110 (the change), #19939 (the value-slot dialect).
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-09T10:01Z. ⛔ Not a claim, ⛔ not a dispatch.
Triage: the edit is to skills/objectstack-automation/** (SKILL.md and evals/flows-triggers-approvals.json). That puts it in domain:skills. It is governed text (Tier H), so the PR lands through the governed-surface endgame: a maintainer's APPROVED review, then the owning seat.
Claim: PM loop round 3
Session: session_01JmWtcHfGbC4ncw4GFKWuRA
Account: os-elon-musk (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-22454-automation-skill-text-slot-delimiter
Worktree: objectstack-issue-22454
Domain: domain:skills
Seat: domain:skills#1
File surface: skills/objectstack-automation/SKILL.md (on origin/main587bd969: the notify example at lines 103–116 — title: 'Done: {record.title}' / message: 'Closed by {$User.Id}' — and the text-slot paragraph at lines 236–241 saying text slots keep the single-brace template; each remaining slot that paragraph names (inputs, httpurl / body, filter) is re-read against what main enforces today — packages/spec/src/automation/flow-text-slot-template.ts for the text slots, the value-slot rules for the rest — and restated to what the doors do, ⛔ no guidance beyond what main enforces), skills/objectstack-automation/evals/flows-triggers-approvals.json eval id 2 (its expected_output asks for "title with single-brace interpolation" and its assertions.must_not_contain carries "{{" — both flipped to the {{ }} delimiter so the eval asserts what main accepts), plus any other single-brace TEXT-slot example the enumeration pin hits under skills/objectstack-automation/** (the seat's own reading: a git grep for title / message / description keys carrying a {…} token hits exactly SKILL.md:108–109; {{ appears once in SKILL.md and once in the eval). Tier H (skills/** is governed): the PR stays draft with the four-piece set and the maintainer merges it. ⛔ No file held by an open PR (15 open PRs' file lists read at 2026-10-09T11:17Z: none touches skills/**). Net-line budget for skills/objectstack-automation/** (1,092 lines today, SKILL.md 439): 0 preferred, at most +2 with a stated reason per line; ⛔ no re-wrap; operative text carries no issue number. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: CONTRACT_REVIEW_TIER (MANDATORY: dispatch-gates --tier --repo objectstack-ai/objectstack skills/objectstack-automation/SKILL.md skills/objectstack-automation/evals/flows-triggers-approvals.json ⇢ 'skills/**' — clause ① (2026-09-10 ruling, verbatim 「必须 fable的还包括对外发布的skills」): the published catalog ships verbatim to third parties by npx skills add objectstack-ai/objectstack/skills and npm create objectstack, so a wrong edit is installed elsewhere before anyone here reads it — and no one-line exemption applies under this root)
Clause-②: no
Responsibility: the published skill text produces the risk (SKILL.md:108–109 and :236–241 prescribe the single-brace delimiter in notify text slots, which the build doors and the save door refuse since PR #22315 with the hole spelling as the remedy) | the platform path that already covers it: the doors' refusal — loud, after the author has written the wrong flow | who reaches it: every AI author who installs objectstack-automation by npx skills add, on the v18 line; used today
Thread-read: 6078701718
Serial constraints cleared: skills/objectstack-automation/ last touched ee6aa013 (2026-10-08) — no same-day churn; no open PR touches skills/**; this seat's own PR #22458 (.claude/**, scripts/pm/label-write.mjs, in the merge queue) and PR #22460 (scripts/pm/fleet-write/*, rest-channel.md, re-merging behind the landed #22457) are file-disjoint from this card; the value-slot sibling #19939 is pm:queue in the spec lane and untouched here (this card rewrites text-slot guidance and re-reads the value-slot sentence against main without widening it); verify lock LOCKED; the lane holds no open p1. Readings at 2026-10-09T11:17Z.
{
"issue": 22454,
"status": "done",
"branch": "claude/issue-22454-automation-skill-text-slot-delimiter",
"pr": "https://github.com/objectstack-ai/objectstack/pull/22475",
"head": "057ce436",
"session": "session_01JmWtcHfGbC4ncw4GFKWuRA",
"premise_still_valid": true,
"summary": "The three sites now say what `main` enforces: the SKILL.md notify example reads `title: 'Done: {{ record.title }}'` and `message: 'Closed {{ record.closed_at | date:long }}'` (the old `{$User.Id}` body has no hole spelling — the door says to compute it into a variable first — so the example became a path-plus-formatter the door accepts and renders); the dialect paragraph is three statements, one door each (text slots render `{{ }}` holes and `os validate` / `registerFlow` refuse a `{…}` token with its `{{ }}` spelling; `{$User.Id}` / `{NOW()}` have no hole and `{{ $User.Id }}` renders blank — assign a variable first; `recipients` / `inputs` / `http` / `filter` keep the single brace), the `{{x}}`-is-template-field clause deleted; eval id 2 expects `title: 'Won: {{ record.name }}'`, `must_contain` gains `{{`, `must_not_contain` drops it. Two § Filter tokens sentences that listed text slots as single-brace positions were corrected, and the section's lede (restated twice elsewhere) was deleted to pay the token ratchet. Draft PR #22475 against main, Tier H, never readied; skip-changeset + assignee os-elon-musk written through label-write.",
"tests": "Doors measured on the built dists (lint closure built under the verify lock at 057ce436, 129 s): NotifyConfigSchema.safeParse — new example ACCEPTED; old `title: 'Done: {record.title}'` REFUSED 'Write `Done: {record.title}` as `Done: {{ record.title }}`'; old `message: 'Closed by {$User.Id}'` REFUSED '`{$User.Id}` is not a variable, so no hole spells it: compute it into a variable with an `assignment` node … and write `{{ v }}` here'; eval title `'Won: {{ record.name }}'` ACCEPTED; `'By {{ $User.Id }}'` ACCEPTED. validateExpression('template', …) compiles all four. templateEngine.evaluate: 'Done: {{ record.title }}' → 'Done: Fix login'; 'Closed {{ record.closed_at | date:long }}' → 'Closed October 9, 2026'; 'By {{ $User.Id }}' → 'By ' (ok: true, blank). Pin: git grep -P for a title/message/description key whose quoted value holds a `{` with no `{` on either side — base d87dff67: SKILL.md:108, :109; head 057ce436: 0 hits in skills/objectstack-automation and 0 across skills/. Token ratchet: SKILL.md 5783/5785, eval 1253/1255, exit 0. Control-byte grep over both files: none. Skill eval run: NOT MEASURED — no runner in this repository reads must_contain / must_not_contain (tree grep finds only the eval JSONs and two READMEs); objectui's check-skill-eval-tokens.mjs matches whole tokens case-sensitively, degrading to an exact substring at a non-identifier end.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (change set from merge base d87dff67, no paths) derived 24 commands at 057ce436 — identical to the path-derived list the dispatch named; each run with its exit captured before any pipe (ran.list `cmd :: exit N`); all 24 exit 0 with verdict lines read (check-skills-token-ratchet + self-test, check:skill-identifier-liveness, check:skill-docs, check:doc-formula-expressions, check:skill-compatibility, check:skill-frame-sync, check:nul-bytes, check:doc-authoring, check:corpus-claim-drift, check:cross-package-test-inputs, check:pm-governed-merges, check:agent-test-spelling, check:driver-memory-census, check:gitlink-declared, check:refd-timer-probe, check:role-word, check:watch-hint-literal, check-ci-filter-parity, check-closing-keyword-parity + self-test, check-comment-mask-corpus, check-doc-route-spelling --advisory + self-test). --ran reconciliation: 24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Derivation printed STALE TREE — 3 commits behind origin/main (c512c255), two derivation inputs changed (scripts/check-durability-degradation-log-level.mjs, scripts/measure-durability-swallow-family.mjs), neither in the list; origin/main not merged in (its commits carry merge=os-regen spec artifacts). CI on the PR: in_progress at report time; not waited for.",
"line_budget": "SKILL.md 439 → 438 lines (−1), 23,052 → 23,129 bytes (+77), ratchet 5,763 → 5,783 tokens (ceiling 5,785, headroom 2); eval 55 → 55 lines, 5,018 → 5,012 bytes (−6), 1,255 → 1,253 tokens (ceiling 1,255); package 1,092 → 1,091 lines. No line added; the text-slot sentences are paid by deleting the § Filter tokens lede (restated by its two bullets and the routing table) and the now-false `{{x}}` clause; no re-wrap paid a line; no ceiling moved (the ratchet script is outside the claimed surface).",
"deviations": [
"PM assumption 3 is half-true: #19939 is open and pm:queue, but its C half (fields.* / assignments.* refuse `{…}`, CEL spelling prescribed; date macros and {$User.*} kept) landed in #22259 (0e9e7b70) — the skill's item 1 already matched it; value-slot guidance untouched.",
"PM assumption 7: no LINE ratchet covers skills/** (check-skill-line-ratchet.mjs excludes the published catalog by design), but a TOKEN ratchet does (scripts/check-skills-token-ratchet.mjs, ceil(bytes/4), shrink-only): SKILL.md had 88 bytes of headroom and the eval 2 bytes, which — not the line count — bounded the rewrite.",
"The dispatch's enumeration regex `\\{[^{]` also matches the second brace of a `{{ ` hole, so the ruling's 0-hit pin was read with a lookaround form (a `{` with no `{` on either side); positive control on the base: 2 hits.",
"Edits beyond the three named sites, all inside the claimed file surface: § Filter tokens lines 207–208 (`title`, `message` dropped from the single-brace list), 213–214 (message body → a `{{ }}` hole), and the two-line section lede deleted to pay the token ratchet — flagged in the PR body for the maintainer.",
"origin/main moved from 587bd969 (dispatch) to d87dff67 (base, fetched at start) and then to c512c255 during the run; the branch is based on d87dff67 and was not re-merged.",
"Labels on the PR not set by this run: `documentation` and `size/s` (labeler / size-labeler); left alone."
],
"files_changed": [
"skills/objectstack-automation/SKILL.md",
"skills/objectstack-automation/evals/flows-triggers-approvals.json"
],
"mcp_calls": "0 — none",
"api_writes": "3 strokes / 4 REST writes, all through scripts/pm/ as objectstack-fleet[bot]: pr_create → POST /repos/objectstack-ai/objectstack/pulls (fleet-write relay run 37926484670, read back identical, 11468 bytes); label-write → POST /repos/objectstack-ai/objectstack/issues/22475/labels (skip-changeset) + POST .../issues/22475/assignees (os-elon-musk) (relay run 37926571692, read back ok); post-stamped → POST /repos/objectstack-ai/objectstack/issues/22454/comments (this report). git push ×2 (empty-branch probe, then 057ce436) — not REST.",
"open_questions": [],
"out_of_scope_findings": [
"class: none (read-only inference) · SKILL.md:154 `The handler reads {NODE_ID.error} (or run-wide {$error})` names no slot; in a text slot it is now `{{ n1.error }}` / `{{ $error.message }}`, in a value-like position still single-brace; the door names the spelling loudly · carrier: 承接者:无 — noted in Acceptance notes, not filed",
"class: none (polish) · the eval's token ceiling is lowerable 1,255 → 1,253 in scripts/check-skills-token-ratchet.mjs, outside this card's surface · carrier: 承接者:无 — noted, not filed",
"class: none (read-only inference, no named producer) · `{{ $User.Id }}` in a text slot renders blank with ok: true and passes objectstack validate (validate-flow-template-paths.ts skips an unresolvable root; lint-flow-patterns.ts reads a bare `$` only outside holes); the skill paragraph now warns · dedupe: text slot $User hole blank validate · carrier: 承接者:无 — noted, not filed"
]
}
Posted 2026-10-09T11:55Z by the dev subagent of session_01JmWtcHfGbC4ncw4GFKWuRA; PR #22475 stays draft (Tier H).
ACCEPT — PR #22475 (head 057ce436), Tier H, the four-piece set posted, landing on the maintainer's APPROVED — skills seat 1, session_01JmWtcHfGbC4ncw4GFKWuRA, 2026-10-09T12:01Z
Verified on GitHub and on the fetched branch, not on the report: a draft PR against main, first line Fixes #22454 (the only closing keyword in the body), 2 files (+17/−18): the notify example now title: 'Done: {{ record.title }}' / message: 'Closed {{ record.closed_at | date:long }}' (measured on the built dists: accepted by NotifyConfigSchema, rendered by the engine; the old lines refused with the door's remedies); the dialect paragraph three statements, one door each, the false {{x}} clause gone; eval id 2 expects title: 'Won: {{ record.name }}' with {{ moved from must_not_contain to must_contain; the § Filter tokens bullets no longer list text slots as single-brace positions and the section's lede (restated at lines 161–162 and in its own second bullet) deleted to pay the token ratchet. SKILL.md 439 → 438 lines; token ratchet 5,783 / 5,785 and 1,253 / 1,255, shrink-only, exit 0. Pin: a text-slot value holding a lone { — 0 hits across skills/ on the head (2 on the base, the positive control). Gates: the dev's 24-family union pinned to 057ce436 (--ran 24/24, all exit 0); CI on the head at this write: four jobs still in_progress, nothing red — the landing waits for them and for the approval anyway. mcp_calls 0; api_writes 3 relay strokes (pr_create, label-write, the report 6080357455) — skip-changeset and the assignee read back. Commit authored by objectstack-fleet[bot]. Deviations accepted as listed in the review record (two mechanism assumptions corrected by measurement; the edits beyond the three sites are inside the claimed file and paid). NOT MEASURED: the skill eval run (no runner in this repository reads the assertions).
Contract review PASS in seat at tier: 6080468777. Landing: Tier H (skills/**) — the four-piece set is posted in this act (this ACCEPT, the review record, needs-user-decision + 维护者速读 on the PR, review requested from os-zhuang and hotlong through the relay); on an authorized APPROVED the seat lands unless the approver already did; close-out is the seat's either way. Out-of-scope: the {{ $User.Id }} blank render in a text slot is filed for the spec lane (link follows on this card); the rest stays in Acceptance notes.
Landed — PR #22475 MERGED by the approver, card closed by Fixes — skills seat 1, session_01JmWtcHfGbC4ncw4GFKWuRA, 2026-10-09T13:04Z
Two readings, taken together: PR #22475 reads merged: true at 2026-10-09T13:02Z (commit 8b713fad783e23d4313fa7d291b88de0bde6efd7, merged through the merge queue after os-zhuang's APPROVED 2026-10-09T12:24Z — review 5469966482 — and their own ready flip, arm (merge) and enqueue at 12:27Z; thirty-five minutes in the queue), and that commit is an ancestor of origin/main as fetched in this act — a single-parent squash commit: the merge queue squashes with its own method whatever the arm said (the approver's arm read merge; shift 1's two-parent commit on PR #22382 was therefore not a queue merge of this kind) — the MERGED proof is by content, never by parent count. The two files are byte-identical to the PR head 057ce436 (git diff 057ce436 <merge commit> -- skills/objectstack-automation/SKILL.md …/evals/flows-triggers-approvals.json is empty); the published skill now teaches the {{ }} delimiter in the flow text slots, the lone-{ text-slot pin reads 0 across skills/.
Tier H landing by the maintainer's authorized approval on this seat's four-piece set (contract review PASS 6080468777, ACCEPT 6080477431, 维护者速读 6080482877, review requested from both authorized approvers). The card closed completed by Fixes; pm:dispatched and the assignee are stripped in this act, and so is the PR's needs-user-decision. Timings: claim → draft PR 35 min; four-piece set → APPROVED 22 min; APPROVED → MERGED 38 min. The out-of-scope finding is filed as #22477 (spec lane, the {{ $User.Id }} blank render). Nothing else is owed on this card.
Activity
objectstack-fleet commentedon Oct 9, 2026
Triage: first grade,
priority:p2·domain:skills·target:v18·area:workflow·pm:queue(findingremoved)Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-09T10:01Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: the edit is to
skills/objectstack-automation/**(SKILL.mdandevals/flows-triggers-approvals.json). That puts it indomain:skills. It is governed text (Tier H), so the PR lands through the governed-surface endgame: a maintainer's APPROVED review, then the owning seat.target:v18: [v18] flow text slots: read ADR-0032 §3's{{ }}delimiter instead of single-brace{token}(notify title/message and the other flow string slots), converting only what renders the same #22110 (target:v18, p2) closed at 2026-10-09T09:41Z through PR feat(spec)!: flow text slots read the {{ }} delimiter, refusing a single-brace token with its hole spelling (#22110) #22315. Since then the skill teaches a notifytitle/messagethatmainrefuses at the build doors and the save door. An agent that follows the skill writes a flow that fails validation. That is the AI-error axis, on the v18 line. Same grade as its parent.{token}values in create_record / update_recordfieldsthat PR #22259 (#19939 pass 1) refuses, and its money-rounding sample is CEL integer division #22260 (closed) is the value-slot sibling for PR feat(spec)!: flow value slots refuse the{…}template dialect, naming the CEL spelling of each token (#19939, C half) #22259. It is not this.Direction: the card's own scope. I checked the three sites on
main2b61f2d9d:SKILL.md:108–:109: the notify example;SKILL.md:236–:241: the text-slot paragraph;expected_output.Restate them in
{{ }}, as ADR-0032 §3 and PR #22315's changeset spell it.inputs,httpurl/body,filter) against whatmainnow enforces, including [v18] retire the{var}template dialect in flow assignment slots: refuse at registration with per-spelling remedies (the C half of #11182 ruling D, on the v18 train) #19939's passes. Each sentence then says what the door does today. ⛔ No guidance beyond whatmainenforces.git grepfor single-brace notify examples underskills/objectstack-automation/**returns 0.objectstack-fleet commentedon Oct 9, 2026
Claim: PM loop round 3
Session:
session_01JmWtcHfGbC4ncw4GFKWuRAAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22454-automation-skill-text-slot-delimiterWorktree:
objectstack-issue-22454Domain:
domain:skillsSeat:
domain:skills#1File surface:
skills/objectstack-automation/SKILL.md(onorigin/main587bd969: the notify example at lines 103–116 —title: 'Done: {record.title}'/message: 'Closed by {$User.Id}'— and the text-slot paragraph at lines 236–241 saying text slots keep the single-brace template; each remaining slot that paragraph names (inputs,httpurl/body,filter) is re-read against whatmainenforces today —packages/spec/src/automation/flow-text-slot-template.tsfor the text slots, the value-slot rules for the rest — and restated to what the doors do, ⛔ no guidance beyond whatmainenforces),skills/objectstack-automation/evals/flows-triggers-approvals.jsoneval id 2 (itsexpected_outputasks for "titlewith single-brace interpolation" and itsassertions.must_not_containcarries"{{"— both flipped to the{{ }}delimiter so the eval asserts whatmainaccepts), plus any other single-brace TEXT-slot example the enumeration pin hits underskills/objectstack-automation/**(the seat's own reading: agit grepfortitle/message/descriptionkeys carrying a{…}token hits exactly SKILL.md:108–109;{{appears once in SKILL.md and once in the eval). Tier H (skills/**is governed): the PR stays draft with the four-piece set and the maintainer merges it. ⛔ No file held by an open PR (15 open PRs' file lists read at 2026-10-09T11:17Z: none touchesskills/**). Net-line budget forskills/objectstack-automation/**(1,092 lines today, SKILL.md 439): 0 preferred, at most +2 with a stated reason per line; ⛔ no re-wrap; operative text carries no issue number. Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: CONTRACT_REVIEW_TIER(MANDATORY:dispatch-gates --tier --repo objectstack-ai/objectstack skills/objectstack-automation/SKILL.md skills/objectstack-automation/evals/flows-triggers-approvals.json⇢ 'skills/**' — clause ① (2026-09-10 ruling, verbatim 「必须 fable的还包括对外发布的skills」): the published catalog ships verbatim to third parties bynpx skills add objectstack-ai/objectstack/skillsandnpm create objectstack, so a wrong edit is installed elsewhere before anyone here reads it — and no one-line exemption applies under this root)Clause-②: no
Responsibility: the published skill text produces the risk (SKILL.md:108–109 and :236–241 prescribe the single-brace delimiter in notify text slots, which the build doors and the save door refuse since PR #22315 with the hole spelling as the remedy) | the platform path that already covers it: the doors' refusal — loud, after the author has written the wrong flow | who reaches it: every AI author who installs
objectstack-automationbynpx skills add, on the v18 line; used todayThread-read: 6078701718
Serial constraints cleared:
skills/objectstack-automation/last touchedee6aa013(2026-10-08) — no same-day churn; no open PR touchesskills/**; this seat's own PR #22458 (.claude/**,scripts/pm/label-write.mjs, in the merge queue) and PR #22460 (scripts/pm/fleet-write/*,rest-channel.md, re-merging behind the landed #22457) are file-disjoint from this card; the value-slot sibling #19939 ispm:queuein the spec lane and untouched here (this card rewrites text-slot guidance and re-reads the value-slot sentence againstmainwithout widening it); verify lock LOCKED; the lane holds no open p1. Readings at 2026-10-09T11:17Z.objectstack-fleet commentedon Oct 9, 2026
os-dev-report
{ "issue": 22454, "status": "done", "branch": "claude/issue-22454-automation-skill-text-slot-delimiter", "pr": "https://github.com/objectstack-ai/objectstack/pull/22475", "head": "057ce436", "session": "session_01JmWtcHfGbC4ncw4GFKWuRA", "premise_still_valid": true, "summary": "The three sites now say what `main` enforces: the SKILL.md notify example reads `title: 'Done: {{ record.title }}'` and `message: 'Closed {{ record.closed_at | date:long }}'` (the old `{$User.Id}` body has no hole spelling — the door says to compute it into a variable first — so the example became a path-plus-formatter the door accepts and renders); the dialect paragraph is three statements, one door each (text slots render `{{ }}` holes and `os validate` / `registerFlow` refuse a `{…}` token with its `{{ }}` spelling; `{$User.Id}` / `{NOW()}` have no hole and `{{ $User.Id }}` renders blank — assign a variable first; `recipients` / `inputs` / `http` / `filter` keep the single brace), the `{{x}}`-is-template-field clause deleted; eval id 2 expects `title: 'Won: {{ record.name }}'`, `must_contain` gains `{{`, `must_not_contain` drops it. Two § Filter tokens sentences that listed text slots as single-brace positions were corrected, and the section's lede (restated twice elsewhere) was deleted to pay the token ratchet. Draft PR #22475 against main, Tier H, never readied; skip-changeset + assignee os-elon-musk written through label-write.", "tests": "Doors measured on the built dists (lint closure built under the verify lock at 057ce436, 129 s): NotifyConfigSchema.safeParse — new example ACCEPTED; old `title: 'Done: {record.title}'` REFUSED 'Write `Done: {record.title}` as `Done: {{ record.title }}`'; old `message: 'Closed by {$User.Id}'` REFUSED '`{$User.Id}` is not a variable, so no hole spells it: compute it into a variable with an `assignment` node … and write `{{ v }}` here'; eval title `'Won: {{ record.name }}'` ACCEPTED; `'By {{ $User.Id }}'` ACCEPTED. validateExpression('template', …) compiles all four. templateEngine.evaluate: 'Done: {{ record.title }}' → 'Done: Fix login'; 'Closed {{ record.closed_at | date:long }}' → 'Closed October 9, 2026'; 'By {{ $User.Id }}' → 'By ' (ok: true, blank). Pin: git grep -P for a title/message/description key whose quoted value holds a `{` with no `{` on either side — base d87dff67: SKILL.md:108, :109; head 057ce436: 0 hits in skills/objectstack-automation and 0 across skills/. Token ratchet: SKILL.md 5783/5785, eval 1253/1255, exit 0. Control-byte grep over both files: none. Skill eval run: NOT MEASURED — no runner in this repository reads must_contain / must_not_contain (tree grep finds only the eval JSONs and two READMEs); objectui's check-skill-eval-tokens.mjs matches whole tokens case-sensitively, degrading to an exact substring at a non-identifier end.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (change set from merge base d87dff67, no paths) derived 24 commands at 057ce436 — identical to the path-derived list the dispatch named; each run with its exit captured before any pipe (ran.list `cmd :: exit N`); all 24 exit 0 with verdict lines read (check-skills-token-ratchet + self-test, check:skill-identifier-liveness, check:skill-docs, check:doc-formula-expressions, check:skill-compatibility, check:skill-frame-sync, check:nul-bytes, check:doc-authoring, check:corpus-claim-drift, check:cross-package-test-inputs, check:pm-governed-merges, check:agent-test-spelling, check:driver-memory-census, check:gitlink-declared, check:refd-timer-probe, check:role-word, check:watch-hint-literal, check-ci-filter-parity, check-closing-keyword-parity + self-test, check-comment-mask-corpus, check-doc-route-spelling --advisory + self-test). --ran reconciliation: 24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Derivation printed STALE TREE — 3 commits behind origin/main (c512c255), two derivation inputs changed (scripts/check-durability-degradation-log-level.mjs, scripts/measure-durability-swallow-family.mjs), neither in the list; origin/main not merged in (its commits carry merge=os-regen spec artifacts). CI on the PR: in_progress at report time; not waited for.", "line_budget": "SKILL.md 439 → 438 lines (−1), 23,052 → 23,129 bytes (+77), ratchet 5,763 → 5,783 tokens (ceiling 5,785, headroom 2); eval 55 → 55 lines, 5,018 → 5,012 bytes (−6), 1,255 → 1,253 tokens (ceiling 1,255); package 1,092 → 1,091 lines. No line added; the text-slot sentences are paid by deleting the § Filter tokens lede (restated by its two bullets and the routing table) and the now-false `{{x}}` clause; no re-wrap paid a line; no ceiling moved (the ratchet script is outside the claimed surface).", "deviations": [ "PM assumption 3 is half-true: #19939 is open and pm:queue, but its C half (fields.* / assignments.* refuse `{…}`, CEL spelling prescribed; date macros and {$User.*} kept) landed in #22259 (0e9e7b70) — the skill's item 1 already matched it; value-slot guidance untouched.", "PM assumption 7: no LINE ratchet covers skills/** (check-skill-line-ratchet.mjs excludes the published catalog by design), but a TOKEN ratchet does (scripts/check-skills-token-ratchet.mjs, ceil(bytes/4), shrink-only): SKILL.md had 88 bytes of headroom and the eval 2 bytes, which — not the line count — bounded the rewrite.", "The dispatch's enumeration regex `\\{[^{]` also matches the second brace of a `{{ ` hole, so the ruling's 0-hit pin was read with a lookaround form (a `{` with no `{` on either side); positive control on the base: 2 hits.", "Edits beyond the three named sites, all inside the claimed file surface: § Filter tokens lines 207–208 (`title`, `message` dropped from the single-brace list), 213–214 (message body → a `{{ }}` hole), and the two-line section lede deleted to pay the token ratchet — flagged in the PR body for the maintainer.", "origin/main moved from 587bd969 (dispatch) to d87dff67 (base, fetched at start) and then to c512c255 during the run; the branch is based on d87dff67 and was not re-merged.", "Labels on the PR not set by this run: `documentation` and `size/s` (labeler / size-labeler); left alone." ], "files_changed": [ "skills/objectstack-automation/SKILL.md", "skills/objectstack-automation/evals/flows-triggers-approvals.json" ], "mcp_calls": "0 — none", "api_writes": "3 strokes / 4 REST writes, all through scripts/pm/ as objectstack-fleet[bot]: pr_create → POST /repos/objectstack-ai/objectstack/pulls (fleet-write relay run 37926484670, read back identical, 11468 bytes); label-write → POST /repos/objectstack-ai/objectstack/issues/22475/labels (skip-changeset) + POST .../issues/22475/assignees (os-elon-musk) (relay run 37926571692, read back ok); post-stamped → POST /repos/objectstack-ai/objectstack/issues/22454/comments (this report). git push ×2 (empty-branch probe, then 057ce436) — not REST.", "open_questions": [], "out_of_scope_findings": [ "class: none (read-only inference) · SKILL.md:154 `The handler reads {NODE_ID.error} (or run-wide {$error})` names no slot; in a text slot it is now `{{ n1.error }}` / `{{ $error.message }}`, in a value-like position still single-brace; the door names the spelling loudly · carrier: 承接者:无 — noted in Acceptance notes, not filed", "class: none (polish) · the eval's token ceiling is lowerable 1,255 → 1,253 in scripts/check-skills-token-ratchet.mjs, outside this card's surface · carrier: 承接者:无 — noted, not filed", "class: none (read-only inference, no named producer) · `{{ $User.Id }}` in a text slot renders blank with ok: true and passes objectstack validate (validate-flow-template-paths.ts skips an unresolvable root; lint-flow-patterns.ts reads a bare `$` only outside holes); the skill paragraph now warns · dedupe: text slot $User hole blank validate · carrier: 承接者:无 — noted, not filed" ] }Posted 2026-10-09T11:55Z by the dev subagent of
session_01JmWtcHfGbC4ncw4GFKWuRA; PR #22475 stays draft (Tier H).Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
ACCEPT — PR #22475 (head
057ce436), Tier H, the four-piece set posted, landing on the maintainer's APPROVED — skills seat 1,session_01JmWtcHfGbC4ncw4GFKWuRA, 2026-10-09T12:01ZVerified on GitHub and on the fetched branch, not on the report: a draft PR against
main, first lineFixes #22454(the only closing keyword in the body), 2 files (+17/−18): the notify example nowtitle: 'Done: {{ record.title }}'/message: 'Closed {{ record.closed_at | date:long }}'(measured on the built dists: accepted byNotifyConfigSchema, rendered by the engine; the old lines refused with the door's remedies); the dialect paragraph three statements, one door each, the false{{x}}clause gone; eval id 2 expectstitle: 'Won: {{ record.name }}'with{{moved frommust_not_containtomust_contain; the § Filter tokens bullets no longer list text slots as single-brace positions and the section's lede (restated at lines 161–162 and in its own second bullet) deleted to pay the token ratchet. SKILL.md 439 → 438 lines; token ratchet 5,783 / 5,785 and 1,253 / 1,255, shrink-only, exit 0. Pin: a text-slot value holding a lone{— 0 hits acrossskills/on the head (2 on the base, the positive control). Gates: the dev's 24-family union pinned to057ce436(--ran24/24, all exit 0); CI on the head at this write: four jobs stillin_progress, nothing red — the landing waits for them and for the approval anyway.mcp_calls0;api_writes3 relay strokes (pr_create, label-write, the report 6080357455) —skip-changesetand the assignee read back. Commit authored byobjectstack-fleet[bot]. Deviations accepted as listed in the review record (two mechanism assumptions corrected by measurement; the edits beyond the three sites are inside the claimed file and paid). NOT MEASURED: the skill eval run (no runner in this repository reads the assertions).Contract review PASS in seat at tier: 6080468777. Landing: Tier H (
skills/**) — the four-piece set is posted in this act (this ACCEPT, the review record,needs-user-decision+ 维护者速读 on the PR, review requested fromos-zhuangandhotlongthrough the relay); on an authorized APPROVED the seat lands unless the approver already did; close-out is the seat's either way. Out-of-scope: the{{ $User.Id }}blank render in a text slot is filed for the spec lane (link follows on this card); the rest stays in Acceptance notes.objectstack-fleet commentedon Oct 9, 2026
Landed — PR #22475 MERGED by the approver, card closed by
Fixes— skills seat 1,session_01JmWtcHfGbC4ncw4GFKWuRA, 2026-10-09T13:04ZTwo readings, taken together: PR #22475 reads
merged: trueat 2026-10-09T13:02Z (commit8b713fad783e23d4313fa7d291b88de0bde6efd7, merged through the merge queue afteros-zhuang's APPROVED 2026-10-09T12:24Z — review 5469966482 — and their own ready flip, arm (merge) and enqueue at 12:27Z; thirty-five minutes in the queue), and that commit is an ancestor oforigin/mainas fetched in this act — a single-parent squash commit: the merge queue squashes with its own method whatever the arm said (the approver's arm readmerge; shift 1's two-parent commit on PR #22382 was therefore not a queue merge of this kind) — the MERGED proof is by content, never by parent count. The two files are byte-identical to the PR head057ce436(git diff 057ce436 <merge commit> -- skills/objectstack-automation/SKILL.md …/evals/flows-triggers-approvals.jsonis empty); the published skill now teaches the{{ }}delimiter in the flow text slots, the lone-{text-slot pin reads 0 acrossskills/.Tier H landing by the maintainer's authorized approval on this seat's four-piece set (contract review PASS 6080468777, ACCEPT 6080477431, 维护者速读 6080482877, review requested from both authorized approvers). The card closed
completedbyFixes;pm:dispatchedand the assignee are stripped in this act, and so is the PR'sneeds-user-decision. Timings: claim → draft PR 35 min; four-piece set → APPROVED 22 min; APPROVED → MERGED 38 min. The out-of-scope finding is filed as #22477 (spec lane, the{{ $User.Id }}blank render). Nothing else is owed on this card.