Skip to content

docs(skills): correct the automation "Verify your work" passage — conditions fail loudly at registration, node values fail at run time - #12257

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-12092-automation-verify-passage
Aug 26, 2026
Merged

docs(skills): correct the automation "Verify your work" passage — conditions fail loudly at registration, node values fail at run time#12257
os-zhuang merged 1 commit into
mainfrom
claude/issue-12092-automation-verify-passage

Conversation

@os-zhuang

@os-zhuangos-zhuang commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Closes#12092

skills/objectstack-automation/SKILL.md's ## Verify your work opening taught that a typo'd field name, an unknown function, and a {…}-wrapped reference in a condition all fail silently at runtime. Two of those three were false, and the same file's Common Pitfalls row (item 10) said the opposite — so the published skill contradicted itself and taught an AI author to hunt for a silence the platform does not have.

What the landed engine actually does — verified against this tree, not the card

Every behavioural claim in the new text was re-verified against origin/main at eeec62a98:

SurfaceBehaviourEvidence in this tree
Conditions + declared bare-CEL slotsFatal at flow registration — syntax, brace-in-CEL, unknown functionAutomationEngine.validateFlowExpressions (packages/services/service-automation/src/engine.ts:5304) runs the fatal pass over config.condition, edge.condition and every predicate-role slot in FLOW_NODE_EXPRESSION_PATHS, then throws with location + source + corrective hint
Unknown function specificallyRejected as a CEL type fault, never reached at run timecelEngine.compile returns kind: 'type' for PRIOR(status); pinned by packages/formula/src/cel-engine.test.ts ("compile() rejects an unknown function as a type error") and validate.test.ts ("rejects an unknown function call", incl. behind a short-circuit)
Node values (flow-template single-brace dialect)Not function-checked at build; loud at run timevalidateFlowExpressions skips flow-template slots by design — "no validator implements their dialect"; interpolateString throws FlowExpressionFunctionError (builtin/template.ts:55, unknownFunctionError at :167)
Typo'd field nameThe one genuinely quiet casethe schema-aware pass is logger.warn-only ("logged, never thrown… strictly additive"); a near-miss bare ref is a warnings.push did-you-mean in packages/formula/src/validate.ts. checkFieldExistencedoes push a hard error for an unknown record.-prefixed field reference — which is why the new text says os validate errors on that spelling

This does not contradict the value-expression half that landed with #11348 / PR #12093 — it states the same asymmetry from the other side and points at the same named error.

Second edit in the same diff, declared

The Common Pitfalls item 10 tail was tightened in the same commit. It is not drive-by scope: it was the other half of the contradiction the card names, stating the same two facts (unknown function, brace-in-CEL) in longer form. Both facts survive verbatim in meaning:

  • before — An UNKNOWN function (…) **fails the build**. And never wrap a field reference in {…} inside a condition — that's a template brace and fails as CEL: write record.x, not {record.x}.
  • after — An UNKNOWN function (…) and a {…}-wrapped field ref both **fail the build**: a brace is a template, not CEL — write record.x, not {record.x}.

It is also part of how the rewrite pays for itself under the ratchet.

Token budget — ⛔ ceiling untouched, change is token-NEGATIVE

Ceiling stays 12643 (set by #12093 under a quoted maintainer ruling). No ceiling was raised, and none was lowered — the ratchet prints headroom on every run, so the shrink is already visible without editing the shared ceiling map.

ReadingBeforeAfterΔ
skills/objectstack-automation/SKILL.md — tokens1264312642−1
skills/objectstack-automation/SKILL.md — lines992995+3
Published bundle — tokens (all 11 SKILL.md)117851117850−1
Published bundle — lines1051210515+3

Lines rise while tokens fall because the new prose rewraps shorter; the ratchet's unit is ceil(utf8 bytes / 4), and bytes went 50571 → 50568. Paid for by genuine deletion, not a re-wrap: the old passage's redundant closing paragraph ("Remember conditions are bare CEL… only string node fields use {…} templates — see objectstack-formula") is gone, since the new opening states the dialect split precisely, and item 10 was tightened as above.

Gate's own verdict line:

✓ check-skills-token-ratchet: skills/objectstack-automation/SKILL.md is 12642 tokens (ceiling 12643; headroom 1).
✓ check-skills-token-ratchet: 11 published SKILL.md within their ceilings.

Verification — all green at f5d58e095

Gate set derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (11 families matched), re-derived after the commit and unchanged. Each verdict below is the gate's own printed line; exit codes were captured before any pipe.

✓ check-agent-test-spelling: 0 violations — 378 file(s) …
OK: 16 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob. [check:cross-package-test-inputs]
✓ doc authoring guard: 390 files clean — no bare metadata literals.
✓ doc authoring guard: 48 published skill files clean — no internal issue-id references.
✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1449 TS blocks judged clean by @objectstack/formula.
✓ check:doc-formula-expressions (field-level `*When`, #11407): 14 predicate(s) on a statically determinable field layer judged clean; 6 skipped as undeterminable.
✓ check-governed-merges --self-test: 129 assertions …
check-role-word: OK, no new occurrences of the reserved word.
✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 78 workspace packages
✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files
OK: all 96 declared cross-package glob(s) (81 unique) are covered by `core` or `crosspkg` … [check-ci-filter-parity]
✓ check-skills-token-ratchet: 11 published SKILL.md within their ceilings.
check-nul-bytes: OK (scanned 6766 text file(s) … no raw ASCII control bytes).

Plus the three SKILL.md-triggered spec artifact gates AGENTS.md names, which the path derivation scores silent (their populations are generated artifacts) and which a body edit can genuinely stale:

✅ 9 generated files in sync with packages/spec [check:skill-refs]
✅ Skill docs in sync [check:skill-docs]
✅ 256 prose examples type-check across 3 surface(s) [check:skill-examples]

Two of those needed a build prerequisite in a fresh worktree before they measured anything — @objectstack/formula + @objectstack/lint for check:doc-formula-expressions, @objectstack/client-react for check:skill-examples. Both refused loudly rather than reporting a false green; the verdicts above are from the runs after those builds.

No changeset — published-skill prose, nothing user-facing is published by it; skip-changeset applied.

⛔ Governed surface (skills/**) — draft, human merge only. Not to be queued, armed for auto-merge, or flipped ready (AGENTS.md Prime Directive #14).

Review from os-zhuang could not be requested through the API: under the shared agent identity os-zhuang is this PR's author, and GitHub refuses Review cannot be requested from pull request author. Flagged for the PM rather than worked around.


Generated by Claude Code

… loudly, node values fail at run time
The '## Verify your work' opening taught that a typo'd field name, an unknown
function, or a {…}-wrapped reference in a condition all fail SILENTLY at
runtime. Two of the three were false, and the same file's Common Pitfalls row
said the opposite.
AutomationEngine.validateFlowExpressions runs a fatal pass (syntax,
brace-in-CEL, unknown function) over every condition and declared bare-CEL slot
at flow registration and throws; celEngine.compile reports an unknown function
as a type fault, pinned in packages/formula. Only node VALUES take the
single-brace flow-template dialect that no validator implements — an unknown
function there raises FlowExpressionFunctionError at run time.
Rewritten to distinguish the two dialects, with a typo'd field name kept as the
one genuinely quiet case (advisory did-you-mean; os validate still errors on an
unknown record.<field>). The overlapping Common Pitfalls sentence is tightened
in the same edit — it stated the same two facts and was the other half of the
contradiction. Token-negative: 12643 -> 12642 against a 12643 ceiling.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ
@os-zhuangClaude

Copy link
Copy Markdown
ContributorAuthor

Armed for merge under the maintainer's shift-close instruction, 2026-08-25: 「当前任务处理完,合并了就下班。」 — covering the reviewed, ACCEPTed governed drafts of this round (this PR and #12274). ACCEPT record: issue comment 5412670650 on #12092.


Generated by Claude Code

Merged via the queue into main with commit 9c496cbAug 26, 2026
37 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-12092-automation-verify-passage branch August 26, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants

@os-zhuang@claude