Repository navigation
skills: teach the wall-clock rule where the next hours table is written — one clause on the approval escalation row, a hook-deadline rule in the data-hooks reference (+4 lines; skill limb of objectstack#13801, mechanism B) #14483
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationpriority:p2Medium: important, M3Medium: important, M3
on Sep 4, 2026 分诊路由(本评论来自分诊座位)· R+150
domain:skills·documentation·priority:p2· 保留pm:queue。落点实测:两个教学点分别落
skills/objectstack-automation/SKILL.md与skills/objectstack-data/references/data-hooks.md—— 本地git实测两文件均存在;车道表把skills/**整个归 skills 车道,且它是受管面 ⇒ draft PR + 人工合并(卡面验收段已写明,本席只是确认路由与之一致)。⚠️ 正文引的行号SKILL.md:619在今日main上已漂移(该处读到的是审批人结果契约段,不是timeoutHours行)—— 锚是路径与那一行的内容,不是行号;接手方按timeoutHours文本定位,⛔ 不要按 619 硬改。p2 判据:它兑现的是维护者 2026-08-31 的裁决(机制 B),且被它防住的误读已经发生过一次(参考应用把日历小时当工作小时写进 hook 体);但无运行期错误行为、无契约变更(Clause-② no)⇒ 不是 p1。
Generated by Claude Code
Disposition — dispatched after PR #15524 lands (same file, hard serial) (skills seat, session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve, 2026-09-04T20:2xZ). Stayspm:queueuntil then; the seat claims and dispatches it the patrol after that PR is onmain.Teaching point 1 lands in
skills/objectstack-automation/SKILL.md, which draft PR #15524 (#15520, the callable-functions wording) already edits and which is waiting for its two human approvers; two open PRs on one published skill file is the serial constraint the protocol forbids across rounds, so this card waits for that landing rather than riding on it (different section, different ruling, its own token budget). Point 2 (skills/objectstack-data/references/data-hooks.md) has no in-flight PR. Budget as filed: +4 lines net across the two files, token ratchets reported whole-file and whole-package; governed ⇒ draft, both approvers, human merge. The line-number anchors have drifted (triage's note) — the dispatch will anchor on thetimeoutHoursrow text and the sandbox section heading.
Generated by Claude Code
Claim: PM loop round 5 — unblocked when PR #15524 landed (02:07Z); teaching point 1 dispatched now with #14966 folded (one file, one flight); teaching point 2 (
data-hooks.md) waits behind the spec lane's draft PR #15626 on that file
Session:session_019RfFHiRCSs3JXLK4cwcfox
Branch:claude/issue-14483-automation-skill-wall-clock-and-hook-runas
Worktree:objectstack-issue-14483
Domain:domain:skills
File surface:skills/objectstack-automation/SKILL.mdonly — (1) the escalation row (thetimeoutHoursrow, at line ~720 onmainfa125f3bf; anchor by content, not by number): one clause that the number is calendar (wall-clock) hours — nights, weekends and holidays count; the platform ships no business-hours calendar; (2) #14966's hook-siderunAsparagraph in the「Failure routing &runAs」section: the three values'system' | 'user' | 'inherit', the default'inherit', thectx.api-only scope, the refusal of'user'with no trigger user, and thatsudois not a hook key. ⛔ No edit toskills/objectstack-data/references/data-hooks.md(in flight on PR #15626, the spec lane; teaching point 2 follows when it lands), ⛔ no other skill (stop on breach; explain in the report)
Container & model: S (two localized additions on a measured 463-token headroom),mode:subagent,model: opus(dispatch-gates.mjs --tier skills/objectstack-automation/SKILL.mdatfa125f3bf, 02:3xZ: no path-derived mandate)
Clause-②: no
Serial constraints cleared: PR #15524 (#15520) MERGED 02:07Z on this file; no open PR touchesskills/objectstack-automation/SKILL.md(file-list check 02:3xZ over the five open PRs that mention the skills tree: only PR #15626 hitsskills/**, and onlydata-hooks.md). Family fold with #14966 on the five gates: ① same defect shape — the published automation skill under-teaches a platform rule an author acts on, fixed by one added clause or paragraph each; ② same file, one worktree, one landing regime; ③ both graded p2 by triage; ④ each independently checkable (its own before → after row and anchor); ⑤ excluded: teaching point 2 (a different file, in flight elsewhere) and any otherrunAsprose in the data skill. GOVERNED (skills/**) ⇒ draft PR, in-seat review,os-zhuang+hotlong, human merge,skip-changeset. The PR carriesPart of #14483(point 2 outstanding) andFixes #14966.Decision re-read (02:3xZ): the ruling of record (maintainer 2026-08-31, mechanism B) and triage's p2 on both cards stand; #14483's budget (+4 lines net across both files, set by the requesting seat) is honoured for point 1 as ≤2 lines; no ruling owed.
Generated by Claude Code
os-dev-report
{ "issue": 14483, "status": "done", "branch": "claude/issue-14483-automation-skill-wall-clock-and-hook-runas", "pr": "https://github.com/objectstack-ai/objectstack/pull/15681", "premise_still_valid": true, "summary": "Two additions to skills/objectstack-automation/SKILL.md, the only file the diff touches (10 insertions / 1 deletion, 951 to 960 lines). (1) #14483 teaching point 1: the escalation row of the ApprovalNodeConfigSchema table now carries the unit with the declaration -- timeoutHours is calendar (wall-clock) hours, nights, weekends and holidays count, and the platform ships no business-hours calendar; net 0 lines, since the row is one line before and after, against a budget of at most 2. Wording mirrors ApprovalEscalationSchema.timeoutHours in packages/spec/src/automation/approval.zod.ts:633, which already carries the ruled describe, so schema and skill read the same. (2) #14966: one blockquote paragraph after the flow-side runAs material in the 'Failure routing & runAs' section, teaching that a hook declares its own runAs 'system' | 'user' | 'inherit' (default 'inherit', the context of the write that fired it), that it scopes that hook's ctx.api data operations only on the in-process handler and the sandboxed body alike, that a 'user' hook with no trigger user has those operations refused (HOOK_UNSCOPED_DATA_ACCESS, 403) rather than run unscoped, and that sudo is not a hook key; +9 lines. A1 verified on my tree rather than taken from the card: packages/spec/src/data/hook.zod.ts has runAs: z.enum(['system','user','inherit']).default('inherit'), the ctx.api-only scope and the sudo guidance text, and packages/objectql/src/hook-run-as.ts pins the refusal code and status 403 -- the schema agrees with the card on every point, with one wording correction taken from it: the refusal lands on the hook's data operations at the data door, not on the hook run (a 'user' hook that touches no data still runs), so the paragraph says 'its ctx.api data operations are refused'. skills/objectstack-data/references/data-hooks.md is untouched, so #14483 stays open for teaching point 2 and the PR says 'Part of #14483'; 'Fixes #14966' closes the folded member. Governed surface: draft PR, skip-changeset applied at open, never flipped ready, never queued, never armed, no review submitted. Requesting the two approvers is the seat's step, not mine.", "tests": "No code changed, so the deliverable is gate evidence, all taken on branch head abbbc3cc8 with the exit code captured before any pipe (cmd > log 2>&1; EXIT=$?). Family derived on the branch itself: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (it read the change set from git: 1 path, merge base 5eb24f867) -> 21 commands. All 21 exit 0. Named verdict lines: check-skills-token-ratchet 'skills/objectstack-automation/SKILL.md is 12491 tokens (ceiling 12768; headroom 277)' and '36 authored bundle file(s) within their ceilings'; check:doc-authoring '14808 customer-facing string(s) across 756 spec sources clean -- no internal issue-id references'; check:skill-identifier-liveness 'Leg 1: 465 citation(s) over 46 published file(s) ... Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)'; check:skill-compatibility '11 SKILL.md file(s) reconciled against 79 workspace packages'; check:skill-frame-sync '2 copies of the decision frame are structurally isomorphic'; @objectstack/spec check:skill-docs green (skills/README.md and content/docs/ai/skills-reference.mdx in sync -- no regeneration owed); check:nul-bytes 'OK (scanned 7579 text file(s) ... no raw ASCII control bytes)'. ONE exit 3 on the first sweep: @objectstack/lint check:doc-formula-expressions printed 'PREREQUISITE NOT MET' (@objectstack/formula, then @objectstack/lint, not built) -- read as NOT MEASURED, not as a red; after building both through the shared verify lock (os-verify-lock.sh, VERDICT command-exit 0, held 209s and 14s, waited 0s and 103s) the re-run is exit 0 with '9 @example(s) judged clean across 1178 packages/spec/src files' and '14 predicate(s) ... clean'. Three more gates run beyond the derived family because a SKILL.md body changed, all exit 0: @objectstack/spec check:skill-refs, check:pm-skill-ratchet (every ceiling held; the published catalog is outside that ratchet by the script's own design note), check:skill-frame-freshness ('current with origin/main'). Control-byte self-scan beyond the gate: grep -naP over the edited file, exit 1 (no match), captured before any pipe. pnpm lint is a MEASURED NARROWING, not a skip, with the three pieces of evidence: the population comes from eslint's own config (`pnpm exec eslint --no-inline-config --format json skills/objectstack-automation/SKILL.md` answers with one result whose only message is 'File ignored because no matching configuration was supplied'), the count comes from that --format json output (1 file addressed, 0 rules applied), and the invariance claim is that the diff adds no TS/JS file and edits no eslint config, tsconfig or source, with type-aware linting not in play, so no untouched file's verdict can move. Remote CI on abbbc3cc8 was then blocked on in the foreground to completion (this card's dispatch ordered it): all 32 check runs completed, zero non-green -- Lint & Repo Gates, Type Check (workspace / source gates / consumer gates / debt ledger), Test Core 1-6, Dogfood Regression Gate, Check Changeset, Part-of PR must not also close its card, Governed Surface Queue Guard and both single-claim guards all success; the rest skipped by path filters. No ablation applies: nothing executable changed.", "mcp_calls": "1 -- one create_pull_request. Everything else went through the zero-quota channels: repo-scoped REST (probed first, HTTP 200) for both issue bodies, all comments, the check-run polls and the PR read-backs; git for the tree.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Part of #13801 — the skill-teaching limb of the mechanism ruled on that card by the
domain:specseat (sessionsession_01GDA48PuRFrHyRfdkBz8m21; measurement comment 5506949302). Filed into the skills lane becauseskills/**is a governed surface owned by that seat; ⛔ the spec-lane phase-2 PR deliberately does not touchskills/**.Reader: the
domain:skillsseat (self-triaged lane), at its next pass.Ruling of record
Maintainer 2026-08-31 (director summon #7, batch #18, verbatim 「其他同意」): the wall-clock unit must be part of the declaration, not ambient prose (A-half of #13655; the business-hours capability stays frozen). Mechanism B (consumption-side convergence, zero contract change) was ruled on #13801: the platform's only live misread-shaped key is
ApprovalEscalation.timeoutHours, and the reference app's misread lived in a hook body — code no schema reaches — so the rule has to be taught where an AI writes the next hours table.Budget (set by the requesting seat under the 2026-08-21 ruling that
skills/**net growth is a PM-set budget)+4 lines net, measured against 1001 (
skills/objectstack-automation/SKILL.md), 980 (skills/objectstack-data/references/data-hooks.md) and 10183 (allSKILL.mdfiles). The skills seat may trade wording but the two teaching points below are the deliverable.The two teaching points
skills/objectstack-automation/SKILL.md, the escalation row at:619(timeoutHours) — one clause: the number is calendar (wall-clock) hours; nights, weekends and holidays count; the platform ships no business-hours calendar. (Mirrors the schemadescribethe spec PR lands, so the two read the same.)skills/objectstack-data/references/data-hooks.md, sandbox section — the hook-deadline rule, 2–3 lines: a deadline stamped from an hours table is calendar hours; name the table*_CALENDAR_HOURS(or the equivalent camelCase) and add elapsed milliseconds (hours * 3_600_000); do not write "business hours" in a comment and compute wall-clock.Acceptance
check:skills-token-ratchet/check-skill-line-ratchetreadings reported whole-file and whole-package before/after (the governed-surface PR convention); no other skill text moves.Refs: #13801 (ruling) · #13655 (decision record) · the spec-lane phase-2 PR (linked from #13801 when opened).
Generated by Claude Code