[finding] skills/objectstack-ai/SKILL.md:405-406 calls a model-registry promptTemplate.system / .user "a CEL predicate" — those keys are the template dialect ({{var}}), and the AI domain has no CEL site at all #14797
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 3, 2026 Triage — graded.
documentation·priority:p3·pm:queue·domain:skills. Adopted as filed.Verified at
origin/mainmodel-registry.zod.ts—systemanduserareTemplateExpressionInputSchema, and their own describes say "supports{{var}}interpolation". ⇒ The schema contradicts the SKILL.md sentence in its own text, not merely by inference.predicateinmodel-registry.zod.ts→ 0.cel|formula|expressioninai/tool.zod.ts→ 0, confirming the card's true clause as well as its false one.
⭐ Checking both halves is what makes this safe to dispatch: the sentence is one clause wrong and one clause right, and a claimer who rewrites the whole sentence would delete a correct statement (
ToolSchemacarries no expression field) that is worth keeping.Scope — terminal
Replace the false clause: what
os validatechecks in this domain is the metadata shape plus thetemplatedialect ofpromptTemplate.system/.user— and the 5-field cron atknowledge-source.zod.ts:28, which the sentence currently omits. There is no CEL predicate anywhere in the AI domain.⛔ Keep the
ToolSchemaclause — it is true and independently verified above.
⚠️ skills/**is governed ⇒ draft PR, human merge. ⛔ Do not flip ready, enqueue or merge.
⚠️ Shrink-or-neutral against the file's line ceiling. ⛔ Re-measure it at claim rather than trusting the card's "5,476 after the #14305 flight" — line ceilings and line numbers have both drifted inside single shifts this week (#14770 watchedprotocol.tsmove ~70 lines in one).⛔ Do not also edit
skills/README.md:105— that is #14794's half and PR #14795 is in flight on it. Two PRs on the same claim is how this pair turns into a conflict.⛔ Out of scope: #14462 (the ai reference index's
SKILL_MAP) is a different defect in a different lane's file. Named in the card's dedup, correctly not folded in.✅ Dedup accepted — 13 results with #14794 and #14462 correctly distinguished, and the closed three set aside on subject.
Generated by Claude Code
Claim: skills lane seat —
pm:queue→pm:dispatchedand the assignee set in the same write. Dispatching one os-dev flight on the triage's terminal scope (comment 5519720690): replace the false clause atskills/objectstack-ai/SKILL.md:404-406(whatos validatechecks in this domain is the metadata shape plus thetemplatedialect ofpromptTemplate.system/.user, and the 5-field cron atknowledge-source.zod.ts:28; there is no CEL predicate in the AI domain), ⛔ keep the trueToolSchemaclause, ⛔ do not touchskills/README.md:105(PR #14795's), ⛔ #14462 stays out.
Session:session_01LraLgQVGq8egUwfYZpbYt1
Branch:claude/issue-14797-ai-skill-cel-predicate-clause
Worktree:objectstack-issue-14797
Clause-②: yes — the rewritten clause asserts whatos validatechecks on the AI surfaces;needs:contract-reviewon the PR, reviewed in-seat at PASS. Governedskills/**⇒ draft PR; review requests are the seat's step.Re-measured at
origin/main5a5336b399, 2026-09-03T03:29Z: the file is 417 lines, 21,903 B = 5,476 tokens against its ratchet row of 6,806 (check-skills-token-ratchet.mjs:286) — headroom exists, but the lane's shrink-or-neutral rule binds: the honest clause is at most the length of the false one. The sentence is at:404-407; the fencedos validatecomment at:400describes the command platform-wide and is not this claim. No open PR holds this file. First lineFixes #14797;skip-changeset.
Generated by Claude Code
Claim: dev seat (os-dev subagent of the dispatching PM session — same session id, distinct seat)
Session:
session_01LraLgQVGq8egUwfYZpbYt1
Branch:claude/issue-14797-ai-skill-cel-predicate-clause(pushed empty at claim as the write-routing probe — green)
Worktree:/home/user/objectstack-issue-14797
Branch point:5a5336b399db2ef18dd4700f97d579a328197dda— identical to the sha the seat re-measured at, so the:404-407line numbers and the 417-line/21,903 B reading carry over unchanged.Working the triage's terminal scope (comment 5519720690) and the seat's claim: replace the false CEL-predicate clause only; keep the
ToolSchemaclause, thenpm run validatesentence and the platform pointer; do not touch the fenced comment at:400,skills/README.md, or anything belonging to #14462. Shrink-or-neutral, no re-wrap of untouched lines, no new file. Draft PR,skip-changeset+needs:contract-review.
Generated by Claude Code
os-dev-report
{ "issue": 14797, "status": "done", "premise_still_valid": true, "branch": "claude/issue-14797-ai-skill-cel-predicate-clause", "head_sha": "90670f2b4a38b5f4cc6870163870e59efdc7ec28", "pr": "https://github.com/objectstack-ai/objectstack/pull/14819", "pr_state": "draft (governed skills/**, never flipped ready, not enqueued, no auto-merge, no reviewers requested)", "labels_on_pr": ["documentation", "size/xs", "skip-changeset", "needs:contract-review"], "summary": "Replaced the one false clause at skills/objectstack-ai/SKILL.md:404-406. The file no longer tells an author that os validate CEL-checks a model-registry promptTemplate; it now says the domain has no CEL site and that promptTemplate.system / .user are the template dialect. The true ToolSchema clause, the npm run validate sentence and the platform pointer are byte-identical; the fenced comment at :400, skills/README.md and anything belonging to #14462 are untouched. 3 insertions, 3 deletions, one file, 417 lines unchanged.", "before": "It confirms the skill / tool / model metadata conforms to the protocol and that\nany CEL predicate parses and resolves — in this domain that is a model-registry\n`promptTemplate.system` / `.user`; `ToolSchema` carries no expression field of\nany kind. In a scaffolded project the gate is `npm run validate`. See\nobjectstack-platform → **Verify your work**.", "after": "It confirms the skill / tool / model metadata conforms to the protocol. This\ndomain has no CEL site — a model-registry `promptTemplate.system` / `.user` is\nthe `template` dialect (`{{var}}`); `ToolSchema` carries no expression field of\nany kind. In a scaffolded project the gate is `npm run validate`. See\nobjectstack-platform → **Verify your work**.", "claims": [ { "claim": "promptTemplate.system / .user are TemplateExpressionInputSchema", "source": "packages/spec/src/ai/model-registry.zod.ts:121-122" }, { "claim": "their own .describe() text says 'supports {{var}} interpolation'", "source": "packages/spec/src/ai/model-registry.zod.ts:121-122" }, { "claim": "TemplateExpressionInputSchema is dialect 'template' — a bare string becomes { dialect: 'template', source }", "source": "packages/spec/src/shared/expression.zod.ts:116-124 (doc comment :116-120, union :121-124)" }, { "claim": "'predicate' occurs 0 times in the model registry", "source": "grep -c 'predicate' packages/spec/src/ai/model-registry.zod.ts = 0" }, { "claim": "ToolSchema carries no expression field of any kind — the clause KEPT verbatim", "source": "grep -Eic 'cel|formula|expression' packages/spec/src/ai/tool.zod.ts = 0" }, { "claim": "those two keys are the ONLY Expression-typed sites in the whole AI domain", "source": "grep -rn 'ExpressionInputSchema|ExpressionSchema|PredicateSchema|PredicateInputSchema' packages/spec/src/ai/ returns exactly 3 lines: import at model-registry.zod.ts:4 and uses at :121-122; 22 files in the dir, no other hit" }, { "claim": "CEL is a real dialect elsewhere, so the domain claim is a measurement not a definition", "source": "packages/spec/src/shared/expression.zod.ts:99-101 — ExpressionInputSchema is the union whose bare-string shorthand is dialect 'cel'" }, { "claim": "no AI slot is expression-validated by os validate — the rule's own scope table names flow predicates, FLOW_NODE_EXPRESSION_PATHS slots, object validation-rule / formula predicates and UI action visible / disabled predicates, and nothing in ai/", "source": "packages/lint/src/validate-expressions.ts:4-17 header, scope table :34-44; grep for promptTemplate / modelRegistry / knowledgeSource / an ai/ path in that file returns nothing" }, { "claim": "os validate = parse ObjectStackDefinitionSchema + run the authoring rules", "source": "packages/cli/src/commands/validate.ts:7-16 imports, :39-41 description" } ], "premise_false": [ "The card body and the triage both name 'the 5-field cron at packages/spec/src/ai/knowledge-source.zod.ts:28' as the AI domain's OTHER real expression-typed site. Measured at 5a5336b399 it is not one: the field is `cron: z.string().optional()` at knowledge-source.zod.ts:33 (a plain string; :28 is only the doc comment calling it 5-field), and it does not appear in the Expression-schema grep. The dispatch's instruction to write 'and the cron on knowledge sources' into a sentence about expression checking would have replaced one false claim with a second of the same class, so that half was OMITTED and the omission is argued in the PR body. Everything else in the card holds: the CEL clause is false and the ToolSchema clause is true, both re-verified here." ], "gates": [ { "cmd": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands", "exit": 0, "verdict": "gate list derived from the tree of 'objectstack-ai/objectstack' at commit 90670f2b4a — 16 commands over the 1-path change set; re-derived AFTER the last edit" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs", "exit": 0, "verdict": "check-skills-token-ratchet: skills/objectstack-ai/SKILL.md is 5475 tokens (ceiling 6806; headroom 1331). / 36 authored bundle file(s) within their ceilings" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs --self-test", "exit": 0, "verdict": "check-skills-token-ratchet self-test: 64 cases pass." }, { "cmd": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "verdict": "OK: all 133 declared cross-package glob(s) (93 unique) are covered by core or crosspkg" }, { "cmd": "node scripts/check-cross-package-test-inputs.mjs", "exit": 0, "verdict": "OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob." }, { "cmd": "node scripts/check-shard-attestation.mjs", "exit": 0, "verdict": "check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)." }, { "cmd": "node scripts/check-test-completeness.mjs", "exit": 3, "verdict": "PREREQUISITE NOT MET — this gate grades a saved 'turbo run test' log, and no log was named. NOT MEASURED, not red: only the CI test run can produce that log." }, { "cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "verdict": "check:doc-formula-expressions (spec TSDoc, #6763): 9 @example(s) judged clean across 1120 packages/spec/src files" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-docs", "exit": 0, "verdict": "Skill docs in sync" }, { "cmd": "pnpm check:agent-test-spelling", "exit": 0, "verdict": "check-agent-test-spelling: 0 violations — 430 file(s)" }, { "cmd": "pnpm check:corpus-claim-drift", "exit": 0, "verdict": "Scanned: 224 .md/.mdx file(s) across 2 root(s); Rules: 4 row(s) — no violations" }, { "cmd": "pnpm check:cross-package-test-inputs", "exit": 0, "verdict": "All 117 self-test cases passed. / OK: 25 package(s) read outside themselves, all declared" }, { "cmd": "pnpm check:doc-authoring", "exit": 0, "verdict": "doc authoring guard: 14546 customer-facing string(s) across 710 spec sources clean" }, { "cmd": "pnpm check:pm-governed-merges", "exit": 0, "verdict": "check-governed-merges --self-test: 243 assertions" }, { "cmd": "pnpm check:role-word", "exit": 0, "verdict": "Scanned: 224 .md/.mdx file(s) read across 2 root(s) — content/docs 190, skills 34 — no violations" }, { "cmd": "pnpm check:skill-compatibility", "exit": 0, "verdict": "check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages" }, { "cmd": "pnpm check:skill-frame-sync", "exit": 0, "verdict": "check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files" }, { "cmd": "pnpm check:skill-identifier-liveness", "exit": 0, "verdict": "check-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)." }, { "cmd": "pnpm --filter @objectstack/spec check:skill-examples", "exit": 0, "verdict": "256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them (dispatch-named; not in the derived union)" }, { "cmd": "node scripts/check-nul-bytes.mjs", "exit": 0, "verdict": "check-nul-bytes: OK (scanned 8070 text file(s); no raw ASCII control bytes) (dispatch-named; not in the derived union)" }, { "cmd": "os-verify-lock.sh -c 'pnpm --filter @objectstack/spec --filter @objectstack/formula build'", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0 · held the lock 159s · waited 0s" }, { "cmd": "os-verify-lock.sh -c 'turbo run build --filter=@objectstack/lint --filter=@objectstack/client-react --filter=@objectstack/client --concurrency=2'", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0 · held the lock 157s · waited 0s; Tasks: 34 successful, 34 total" } ], "gate_notes": "Every exit code captured by redirect BEFORE any pipe, and every verdict quoted is the gate's own printed line, never a bare $?. Three gates first answered PREREQUISITE NOT MET (exit 3) or refused for want of an install / compiled output; they were re-run to a real verdict after pnpm install and the two locked builds, and the rows above are the post-build runs. check-test-completeness is the only one that stays NOT MEASURED. Whole union re-derived and run at head 90670f2b4a, which is the final commit — no commit landed after the union ran.", "eslint": "A measured TOTAL, not a narrowing. (1) Population read from eslint.config.mjs itself: all 7 files: blocks (:971, :1015, :1054, :1103, :1172, :1212, :1238 via COMMENT_SWALLOW_FILES at :785) are scoped to {ts,tsx,mts,cts,js,jsx,mjs,cjs}; grep for '.md' or 'mdx' in that config returns 0 hits. (2) Count read from --format json: eslint --no-inline-config --format json on the one changed path exits 0 with errorCount 0 and the message 'File ignored because no matching configuration was supplied.' — 0 of 1 changed paths are lintable. (3) Invariance: the config states at :328 there is no parserOptions.project and no typed typescript-eslint rules for ANY block, so no type-aware program couples files; this diff edits no config, manifest, tsconfig or TS/JS source and cannot move an untouched file's verdict.", "token_delta": { "convention": "ceil(utf8 bytes / 4) — scripts/check-skills-token-ratchet.mjs:184 TOKEN_CONVENTION", "file": "skills/objectstack-ai/SKILL.md", "bytes_before": 21903, "bytes_after": 21900, "tokens_before": 5476, "tokens_after": 5475, "token_delta": -1, "byte_delta": -3, "lines_before": 417, "lines_after": 417, "paragraph_bytes_before": 358, "paragraph_bytes_after": 355, "package_delta": "-1 token; the only file touched, no new file", "ceiling_row": "['skills/objectstack-ai/SKILL.md', 6806] at scripts/check-skills-token-ratchet.mjs:286 — untouched; the script's own note at :85-87 makes lowering permitted, not required", "verdict": "SHRINK, not merely neutral — the new clause is shorter than the one it replaced" }, "edit_landed_proof": { "grep_c_CEL_predicate_parses": "1 before, 0 after", "grep_c_no_CEL_site_injected": "0 before, 1 after", "grep_c_ToolSchema": "4 before, 4 after (unchanged)", "grep_c_npm_run_validate": "1 before, 1 after (unchanged)", "diff": "3 insertions(+), 3 deletions(-), 1 file" }, "fence_census": { "fences_before": [31, 37, 94, 115, 181, 185, 242, 258, 399, 402], "fences_after": [31, 37, 94, 115, 181, 185, 242, 258, 399, 402], "os_check_markers_before": [93, 241], "os_check_markers_after": [93, 241], "verdict": "identical — the edit is at :404-408, below every marker, and the line count did not change" }, "tests": "No test change: the diff is five lines of published prose in one Markdown file, and no package publishes from it. The evidence is the gate union above, all at head 90670f2b4a, plus the edit-landed-on-disk proof and the fence census. The contract claims in the new sentence were each read from the spec sources at this branch point rather than recalled — see 'claims'.", "changeset": "None, by route 2. scripts/check-empty-changeset.mjs:359-362 enumerates this exact case in its own words ('It releases nothing (.github/, .claude/, skills/, docs/, content/, examples/, tests-only, and the like)' then apply the skip-changeset label), and the gate pins a skills-only PR carrying NO changeset as GREEN 3 at :559-568. No package version moves.", "channels": "REST is CLOSED for this session — authenticated GET on repo-scoped endpoints returns 403 with 'GitHub access is not enabled for this session', so labels went the MCP fallback: authoritative read (documentation, size/xs) via pull_request_read get, union written whole-set via issue_write, then a COMPARE read-back that parsed the label chips off the PR page and found exactly the union — nothing stripped, nothing added concurrently. issue_read get_labels answered 'API rate limit already exceeded' exactly as the dispatch warned. Bulk issue reading used the zero-quota embedded-JSON payload, not MCP.", "mcp_calls": "8 — add_issue_comment (claim), create_pull_request, pull_request_read get, issue_write (labels), pull_request_read get_status, issue_read get_labels (rate-limited, no data), add_issue_comment (this report), issue_read get_comments (read-back). Issue body and all comments were read zero-quota from the single-card page payload.", "open_questions": [], "out_of_scope_findings": [ "NOT FILED, reported only per dispatch. Same truth class as the clause just fixed, one sentence above it: skills/objectstack-ai/SKILL.md:396 tells the author to run the author-time gate 'After authoring a *.skill.ts / *.tool.ts or a model-registry entry', and the retained clause still says os validate confirms 'model metadata'. But os validate parses ObjectStackDefinitionSchema (packages/spec/src/stack.zod.ts:1184), whose AI collections are exactly agents / tools / skills (STACK_DEFINITION_COLLECTIONS_SHAPE at :264, keys at :561-563). ModelRegistrySchema (ai/model-registry.zod.ts:167) is referenced nowhere outside its own file in non-test code, and grep for 'knowledge', 'modelRegist' or 'promptTemplate' in stack.zod.ts returns 0 — a model-registry entry is not reachable by os validate at all. The file already says as much at :332 ('agents / tools / skills are the only AI stack collections'), so :396 and :332 contradict each other today. Left alone because the triage scope was terminal on the one CEL clause; it wants its own card and its own measurement of what an author should actually run for a model registry.", "NOT FILED, reported only. Declared-but-unenforced, and the reason the card's proposed second half was unwritable: packages/spec/src/ai/knowledge-source.zod.ts:28-30 documents the field as 'Cron expression (5-field)' while :33 types it `cron: z.string().optional()` — a plain string. The spec already ships a purpose-built CronExpressionInputSchema for exactly this (shared/expression.zod.ts:110-113, dialect 'cron'), and it is not used here, so the 5-field promise is enforced nowhere and a value like 'not a cron' parses green. ADR-0049 enforce-or-remove shaped: either type it with the cron schema or stop documenting a shape nothing checks." ] }
Generated by Claude Code
Clause ② contract review — PASS — skills-lane seat (session
session_01LraLgQVGq8egUwfYZpbYt1), done in-seat atCONTRACT_REVIEW_TIER(served model read viaget_sessionat 2026-09-03T01:13Z:session_context.model=last_served_model= the valueCONTRACT_REVIEW_TIERnames onmainsince PR #14644), verified at source onorigin/main5a5336b399at 03:56Z, not from the report.The claim under review (PR #14819 @
90670f2b,skills/objectstack-ai/SKILL.md:404-406): this domain has no CEL site — a model-registrypromptTemplate.system/.useris thetemplatedialect ({{var}});ToolSchemacarries no expression field of any kind.packages/spec/src/ai/model-registry.zod.ts:121-122—system/userareTemplateExpressionInputSchema, each.describe()saying "supports {{var}} interpolation";packages/spec/src/shared/expression.zod.ts:117-124defines that schema as dialecttemplate. The seat's grep forExpressionInputSchema|ExpressionSchema|PredicateSchemaunderpackages/spec/src/ai/returns exactly those two uses plus their import — no other expression-typed site in the domain;ai/tool.zod.tsmatchescel|formula|expression0 times (the kept clause).packages/lint/src/validate-expressions.ts:34-44— the rule's own scope table names object validations, fieldexpression/reference/options, select-optionvisibleWhen, actionobjectNameand sharing-rule conditions; a grep forpromptTemplate/modelRegist/knowledgeSource/ anyai/path in that file returns nothing. Soos validateexpression-checks no AI slot — the old clause promised a check that does not exist.- Premise correction accepted: the card's and the triage's "5-field cron at
knowledge-source.zod.ts:28" is not an expression-typed site —:28-30is a doc comment and:33types itcron: z.string().optional(), a plain string; writing it into a sentence about expression checking would have replaced one false claim with another of the same class. The dev omitted it and argued the omission in the PR body; the seat agrees.
⇒ Per the 2026-08-31 ruling the same seat strips
needs:contract-reviewat PASS: stripped on PR #14819 in this round and read back. This card never carried the label. ACCEPT follows on CI green (PR created 03:49Z; Lint & Repo Gates running).
Generated by Claude Code
ACCEPT — skills-lane seat (session
session_01LraLgQVGq8egUwfYZpbYt1), reviewer of record, verified against GitHub and the seat's own checkout, not the report. Clause ② was passed in-seat at 03:57Z (comment 5520107495) and the label stripped on the PR.⚠️ Correction on record: the seat's 04:00Z seat-post revision said "ACCEPT at green"; this comment is that ACCEPT, posted at 04:41Z after the check-in'sget_commentsread showed none on the card — a self-count is not a witness.- PR docs(skills): the AI domain has no CEL site — correct the os validate clause in objectstack-ai #14819 exists, is DRAFT, head
90670f2b, one file, +3 −3; labels after the stripdocumentation·size/xs·skip-changeset; reviewersos-zhuang+hotlongrequested and read back at 04:12Z. - Diff read by the seat:
skills/objectstack-ai/SKILL.md:404-406— the false "any CEL predicate parses and resolves — in this domain that is a model-registry promptTemplate.system / .user" clause replaced by "This domain has no CEL site — a model-registry promptTemplate.system / .user is the template dialect ({{var}})"; the trueToolSchemaclause, thenpm run validatesentence and the platform pointer byte-identical; the fenced:400comment untouched;skills/README.mduntouched. - Seat re-measured at 2026-09-03T04:12Z: 21,903 → 21,900 bytes = 5,476 → 5,475 tokens (−1) against the unchanged 6,806 row; 417 → 417 lines;
CEL predicate parses1 → 0,no CEL site0 → 1,ToolSchema4 → 4; the twoos:checkmarker lines and all ten fences at identical positions. - Premise correction accepted (already recorded at PASS): the card's and the triage's "5-field cron at
knowledge-source.zod.ts:28" is a plainz.string()(:33), not an expression-typed site — the dev refused to write it into the sentence and argued why; the seat filed the declared-but-unenforced half as [finding]KnowledgeSourceSchema.cronis documented as a 5-field cron expression but typedz.string()— the spec's ownCronExpressionInputSchemais not used, so'not a cron'parses green #14825 for the spec lane. - CI at
90670f2b(read 04:40Z):mergeable_state: clean; run 33712760742 —Test Core (1/6)…(6/6)all success, aggregateTest Coresuccess 03:56:12Z,Dogfood Regression Gatesuccess,filtersuccess; run 33712760559TypeScript Type Checksuccess; run 33712760831Check Changesetsuccess,Auto Labelsuccess. No red check run on the head. - Recorded on the ledger and being filed this check-in after a cleared dedup:
SKILL.md:396tells the author to runos validateafter "a model-registry entry" while:332says agents / tools / skills are the only AI stack collections — a same-class truth defect one sentence above this PR's edit, left alone here as the triage's terminal scope required. - Governed
skills/**⇒ stays DRAFT; human merge is the record. At MERGED the seat stripspm:dispatched(Fixes⇒ the card closes).
Generated by Claude Code
- PR docs(skills): the AI domain has no CEL site — correct the os validate clause in objectstack-ai #14819 exists, is DRAFT, head
Merge patrol reading 2026-09-03T12:13Z (
git fetch origin main+git log origin/main --grep '(#14819)'in the same minute; API head cross-checked): PR #14819 merged asd355c36115(queue commit 09:21:57Z, onmainbetween the seat's 11:27Z and 12:13Z readings); this card was closed by os-zhuang at 11:32:37Z. The correctedos validateclause is onmain.pm:dispatchedremoved in this minute; labels nowdocumentation,domain:skills,priority:p3. The card held serial behind this PR, #14836 (the:396/:404"model-registry entry" deletions one sentence above), is dispatched now.
Generated by Claude Code
Recorded by the skills lane seat (session
session_01LraLgQVGq8egUwfYZpbYt1) from the #14794 flight (PR #14795), which measured it while removing the same false claim fromskills/README.md:105("AI tool params" as a CEL site) and could not take it — noSKILL.mdedit was in that flight's scope. Unassigned, bare, for triage.What
skills/objectstack-ai/SKILL.md:404-407atorigin/main8f9ef6f7c8(read 2026-09-03T02:11Z), under Verify your work:The second clause is true (
packages/spec/src/ai/tool.zod.tsmatchescel|formula|expressionzero times). The first is false:packages/spec/src/ai/model-registry.zod.ts:121-122typessystem/userasTemplateExpressionInputSchema, whichpackages/spec/src/shared/expression.zod.ts:117-124defines as{ dialect: 'template', source }—{{var}}interpolation for "notification subjects/bodies, titleFormat, prompt templates". Not CEL, not a predicate.predicateoccurs 0 times inmodel-registry.zod.ts.So the sentence tells an author that
os validateCEL-checks a prompt template. It does not; a{{var}}template is validated as a template. The AI domain's other real expression-typed site is the 5-field cron atpackages/spec/src/ai/knowledge-source.zod.ts:28— also not CEL — which the sentence omits.Why it matters
Published, customer-loaded surface; same truth class the programme has been clearing (a declared mechanism described as something it is not). An author reading it may write a CEL predicate into a prompt template expecting the gate to catch mistakes, or wonder why a template's
{{var}}is never "resolved" by CEL.Likely resolution, not a decision
One clause in place: what
os validatechecks in this domain is the metadata shape plus thetemplatedialect ofpromptTemplate.system/.user(and the cron on knowledge sources); there is no CEL predicate in the AI domain. Shrink-or-neutral insideskills/objectstack-ai/SKILL.md(ceiling row 5,476 after the #14305 flight; re-measure at claim). Governedskills/**⇒ draft, human merge.Verified
search_issues, 13 results): [finding] Theobjectstack-aigenerated reference index advertises 6 schemas the SKILL.md never teaches and omits the one it names —SKILL_MAPinbuild-skill-references.tsis unreconciled with the body #14462 (open,domain:spec— the ai reference index'sSKILL_MAP, a different defect), skills/README.md truth + routing sweep:OLD/NEW"evaluate tonullsince M9.5" is anchored nowhere and contradicts the formula skill; "AI tool params" is not a CEL site; the cross-skill routing list lacks the upgrade-vs-platform and objectui inbound decision points #14794 (open — the README half, being fixed by PR docs(skills): settle two false claims in skills/README.md and add three cross-skill routing bullets #14795), validateExpression's unknown-function refusal hands the author the dialect prescription - advice that cannot succeed on a source that is already bare CEL #13821 / Gate candidate: named-identifier liveness check over skills/** — a skill row citing a schema/field that greps to zero repo-wide is a red, not a sentence #13678 / objectstack-data skill teaches deleteBehavior:'set_null' on master_detail — wrong before #9689, a parse-time rejection after it #11409 (closed, other subjects). No card carries this sentence.Refs: #14794 · PR #14795 · #14305 (the ai flight) · #14462.