Repository navigation
docs(skills): objectstack-data rules/lifecycle.md teaches the save notice - #28813
Conversation
…tice The data skill's lifecycle rule gains a Save Notice section: ctx.notice for inline handler and sandboxed body alike, info severity distinct from validation warnings and from a record:alert banner, one message per write with the last call winning, and the save_notice flow node. Paid inside the file's token ceiling by deleting the Decision Tree, the telemetry-growth anecdote and a Safety Semantics restatement. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2g7RyXa8ErM6GAkHyc
|
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc Contract reviewServed-tier: Inputs: card #28253 body and all four comments (triage 6532361474, 6563078644; claim 6563777116; dev report 6564123997); PR #28813 body, file list (2 files, +34/−18) and ① Derived judgments
② Semver level
③ Boundary flagsDev report 6564123997, each flag answered:
Boundary facts verified against the dev's facts table: every file:line cited resolves on ④ Design judgment
Claim-by-claim against the cited code:
The three deleted blocks, each against the rest of the file:
Eval scenario verdict: an author who opens this page learns the notice, its spelling on both doors, where it surfaces, and the exact line between it and a Must-fix: none. Should-fix:
Implemented-by: VERDICT: PASS Read at 2026-11-01T21:37Z. |
…anner contrast, reword the intro Contract-review should-fixes: the sandboxed body is named first and the inline handler as the deprecated door, matching the hooks reference; a record:alert banner shows whenever the record's state says so rather than on every visit, since a viewer can dismiss it; the intro no longer reads as contradicting itself about hooks. Paid inside the file's token ceiling by shortening the section heading and one intro clause. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2g7RyXa8ErM6GAkHyc
|
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc Contract reviewServed-tier: Delta round on review 6564252529 (head ① Derived judgments
② Semver level
③ Boundary flagsDelta report 6564403990, each entry answered:
Round-one ③ items 1–3 (labels, SKILL.md untouched, cleanup) stand as answered in 6564252529. ④ Design judgment
The two cuts:
Everything else in the file is byte-identical to the round-one head, whose claim-by-claim verification in 6564252529 stands (hook-notice.ts, engine.ts, hook.zod.ts, data-engine.ts, protocol.zod.ts, the sandbox runners, the two toasts, save-notice-node.ts, save-notice-placement.ts, record-change-trigger.ts, subflow/map nodes; the Decision Tree, anecdote and "Nothing is deleted." deletions lose no taught fact). Eval scenario: unchanged verdict — an author who opens the page is led to Must-fix: none. Should-fix: none. Implemented-by: VERDICT: PASS Read at 2026-11-01T21:53Z. |
|
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc 维护者速读(席位终稿 · head
|
Requested by 田騏 · project thread
Fixes #28253
Clause-②: no
Metadata-protocol: none
维护者速读
objectstack-data技能的rules/lifecycle.md新增「Save Notice」一节:保存钩子用ctx.notice('…')告诉保存者这次保存触发了什么(inlinehandler与沙箱body同一拼法、不需要能力声明),记录触发的 flow 用save_notice节点设同一条消息;info 级、一次保存一条、后设者胜、与校验warnings和record:alert横幅的区别。另附 changeset(@objectstack/skillspatch)。record:alert横幅来「告诉用户」;这是 Save answer: a hook or record-triggered flow can attach one user-facing notice to a record save, shown with the save toast #28000 的 Skills-docs 欠账。skills/objectstack-data/rules/lifecycle.md末尾新节(主要 hunk),以及被删去的「Decision Tree」一节(用它付 token 账)。node scripts/check-skills-token-ratchet.mjs,预期看到rules/lifecycle.md is 1587 tokens (ceiling 1590; headroom 3)且整体✓。skills/**为受管面(Tier H),需要授权账号的 APPROVED 评审后由席位落地。What changes
skills/objectstack-data/rules/lifecycle.mdgains Save Notice — what the save set in motion, teaching what the live code does:ctx.notice('Sent to your manager for approval')— inlinehandlerand sandboxedbodyalike, no capability (HookContext.notice, bound by the engine on every insert/update dispatch; the body runner marshals it as a host function).noticeand the console shows it on the save toast. Info severity: an outcome, never a problem — distinct from validationwarnings, and from arecord:alertbanner (page metadata shown by the record's state on every visit); the notice is for what this save started.save_noticenode (config.message,{{ }}renders); refused in any other flow, and after anapproval/wait.The intro's "not to be confused with lifecycle hooks" sentence now says the page also carries the save notice.
Paid inside the file's token ceiling (no ceiling moves), by deleting restating prose in the same file:
onlyWhen+ rotation/archive);.changeset/28253-skill-save-notice.md—@objectstack/skills: patch(the skill ships in that package'sdist).Skills readings (
skills/**diff, two readings each):rules/lifecycle.mdlinesrules/lifecycle.mdbytes / tokens (ceil(bytes/4))skills/*/SKILL.mdlinesNot touched:
skills/objectstack-data/SKILL.md(PR #28795 is open on it). Its rule index entry forrules/lifecycle.md(line 45) still describes the page as retention/TTL/rotation/archive only and does not name the save notice; if the index must name the new topic, that is a follow-up on that file once #28795 lands.Tests
Docs-only diff in a published skill package: no test file is owed. The gate family that measures the page is the token ratchet, run on the final head:
node scripts/check-skills-token-ratchet.mjs→ exit 0 —rules/lifecycle.md is 1587 tokens (ceiling 1590; headroom 3);57 authored bundle file(s) within their ceilings.Acceptance notes
packages/objectql/src/hook-notice.ts(binding, the non-string refusal, the no-listener no-op),packages/spec/src/data/hook.zod.ts(HookContext.notice, handler and body alike, no capability),packages/runtime/src/sandbox/body-runner.tsandquickjs-runner.ts(the sandbox marshal),packages/spec/src/contracts/data-engine.ts(last call wins, refused write answers its error, nothing stored),packages/spec/src/api/protocol.zod.ts(the answer'snotice, info severity, distinct fromwarnings),ui/packages/react/src/record-save-feedback.ts(the save toast),packages/spec/src/automation/save-notice-placement.tsandpackages/services/service-automation/src/builtin/save-notice-node.ts(the flow node and its refusals).skills/objectstack-data/references/data-hooks.md— the sandboxctx.*table and theHookContextinterface listing carry noctx.noticerow; that file sits at 2 tokens of headroom, so a row there must be paid for by deletion in that file. Carrier: none.skip-changesetdoes not apply (a changeset is included).Verification
Gate derivation on the final head (
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, change set derived from git: 2 files, +34 / −18): 43 families derived; every command recorded with its exit code captured before any pipe, then reconciled with--ran.63afc09f2d(install only, nodist): 38 families exit 0; 5 exit 3 (PREREQUISITE NOT MET, no builtdist):check:doc-formula-expressions(lint),check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:sourcemap-no-sources-content.pnpm build --concurrency=2underscripts/pm/os-verify-lock.sh(VERDICT command-exit 0, 116/117 tasks replayed from the shared turbo cache), then the five re-run on the same head: all exit 0.node scripts/pm/dispatch-gates.mjs --ranover the merged record:43 derived famil(ies) accounted for — 43 run, 0 NOT-MEASURED, 0 UNRUN(exit 0).check:skills-token-ratchet(+--self-test),check:skill-frame-sync,check:skill-identifier-liveness,check:skill-compatibility,check:doc-authoring(the no-tracker-id rule overskills/**),check:pm-skill-id-lint,check:role-word,check:corpus-claim-drift,check:published-files, the changeset gates (check-empty-changeset,check-changeset-no-major,check-adr-0087-registration) — all exit 0.check:dev-prereqs,check:skill-frame-freshness(the diff touches no frame file and nopackages/specsource).Lint & Repo Gates, the type-check lanes and the rest) are the PR's check-runs; nothing there is re-run locally.Dogfood battery: n/a — no
!in the title and no(narrowing)arm.🤖 Generated with Claude Code