Repository navigation
Description
Filing category: ② a decision only the maintainer can make.
维护者速读
- 现象:加班申请里,和一张已批准加班完全相同时段的新申请照样能建、能提交;如果再批一次,调休就记了两遍。请假单同理(同一天请两次)。校验规则只能看当前这一条记录,读不到同一个人的其他记录,所以 AI 和人都写不出"时间不能重叠"的规则。
- 要你裁:平台是否提供"同一人时间段不重叠"的声明式约束。
- 推荐:A:对象级
exclusion约束(分组字段 + 起止字段 + 状态过滤),写入时由服务端查询判定,与唯一索引同一层。
One-sentence problem
Every time-booking app (overtime, leave, room booking, shifts) needs "no two of mine overlap", and the platform's rules cannot see the other records.
Evidence (reach)
Hosted tenant (pnpm dev:stack --with-ui, Team plan; cloud ff373e02, framework d7c3d44e), member's MCP OAuth token:
el5z_ot_req"11月10日版本上线加班" 18:30–21:30, approved, 3 h credited.create_record el5z_ot_req { start_time: '2026-11-10T18:30:00+08:00', end_time: '2026-11-10T21:30:00+08:00', compensation: 'comp_leave', … }→ created (draft), submittable.- A validation
conditionseesrecord,previous, one-hop references; no query over sibling rows. Unique indexes (indexes[].unique) compare equal values only.
Options
| Option | What it does | What the customer sees | Effort |
|---|---|---|---|
| A | Object-level declarative constraint, e.g. exclusions: [{ name, groupBy: ['owner_id'], range: ['start_time', 'end_time'], where: { status: { $ne: 'rejected' } }, message }], checked on insert/update by the data layer with a range query |
"该时段已有加班申请" on save, from AI or form | data + spec seats · 2–3 PRs · precedent: unique indexes |
| B | Let validation scripts call a bounded aggregate, e.g. count('el5z_ot_req', { owner_id: record.owner_id, … }) > 0 |
Same message; authors write the query | formula + data seats · 2 PRs · opens queries inside every validation |
| C | Keep as is; approvers catch duplicates | Double credit unless a person notices | none |
Business reading: A covers the common case with one declared line; B is general but every rule becomes a query; C leaves money/time to human attention.
Recommendation
A. It is the pattern behind every booking app, it stays declarative (lintable, explainable to an agent), and it lives where unique indexes already live. Confidence gap: whether where should be a status filter only or a full filter; recommend the same filter shape summaries use.
Self-check: ① A; ② A or B; ③ A (an agent cannot write B wrong in a way that silently passes); ④ A smaller than B.
After the ruling
A: spec key on the object, data-layer check on write with a range query over the group, lint for unknown fields, AI authoring rule; e2e: second overlapping overtime is refused, an adjacent one (21:30–23:00) is accepted.
os-decision-facets
① 项目长远合理性: A 与唯一索引同层、声明式,可被 lint 与 AI 规则覆盖。
② 实际业务拉动: 加班、请假、会议室、排班都需要;本次实测重复加班可提交。
③ 防 AI 犯错: A 由平台判定;B 让 agent 写查询,易写错且难核验。
④ 创业阶段不扩散: A 一个新约束类型;B 给所有校验开查询能力。
Prior rulings read: none found; thread: none
Reader who acts: the data seat and the spec seat, after the ruling.
Dedupe: repo:objectstack-ai/objectstack is:issue overlapping time range validation cross-record → 11 hits, none on this; validation query other records uniqueness overlap → 14 hits (#8413 closed, turso unique) — none on this.
Activity
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: audit ·
needs-user-decision·domain:spec· p2 · 2026-11-13T01:46Z⛔ Not a claim.
priority:p2anddomain:spec: an object-levelexclusionconstraint is a new declarable key, and by pm-dispatch(grading): grade by impact — the maintainer-approved four-row table, MCP as the focus feature, p3 as the default for follow-ups and process tweaks #32906 an ordinary protocol addition is p2. It is not needed for 18.4.0.Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Brief-claimed-by: session_01Q4EjjMnyLqJdzuktEmRPXH · batch #2 · 2026-11-13T04:46Z
Decision batch #2, taken on the maintainer's 「5张一批按总监决裁格式给我」; batch #1 was answered 「以上原则同意」.
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Ruling recorded · #32979 · A, after 18.4.0 · 2026-11-13T05:20Z
Maintainer, verbatim (triage#1 session): 「32677 暂停,先由元数据项目自己处理。其他同意」, answering decision batch #2 (proposed
32627 1B·2B·3A / 32749 A / 32979 A / 32677 B / 32688 C). The batch was analysed independently at the fable tier, with prior rulings checked first.validation.zod.tssays a SELECT-then-INSERT rule is inherently racy and validation does no I/O.domain:specwrites a one-page design (key shape, interval semantics, existing data, per-driver atomicity) through contract review. Then spec lands the key and authoring checks, and data lands enforcement per driver. Acceptance: a second overlapping record is refused, an adjacent one is accepted, and of two concurrent requests only one succeeds. Scheduled after the 18.4.0 cut:needs-user-decision→pm:on-hold.Restart-when: 18.4.0 is cut (the maintainer's ruling A here, scheduled after the release).
Generated by Claude Code
[-][Decision] How should an app stop the same person filing two records for overlapping time (overtime twice for one evening, leave over leave)?[/-][+]data layer: a declarative exclusion constraint refuses two records of one person over overlapping time (e.g. overtime twice) — ruled A, after 18.4.0[/+]objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: restart →
pm:queue· 2026-11-13T23:07Zobjectstack-fleet commentedon Nov 14, 2026
domain:spec#2 · os-tesla · session_01L9qibvfX5bawZKtfa6u7j9
Claim: PM loop round 3 · 2026-11-14T00:26Z
Session:
session_01L9qibvfX5bawZKtfa6u7j9(seat); card threadsession_01L9qibwo1JzKTz7boR9JXuGis the devAccount:
os-teslaBranch:
claude/project-thread-9apm8i(the card thread's designated branch; the platform lets a thread push only that branch, so notclaude/issue-32979-*)Worktree:
objectstack-issue-32979Domain:
domain:specSeat:
domain:spec#2File surface: step 1 only:
docs/design/exclusion-constraints.md(new) and adocs/design/index row if one exists. ⛔ No schema, lint or driver code;docs/adr/**untouched (stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier,effort: high(fleet token rule 2, maintainer 2026-11-12); the design goes through contract review at tierClause-②: no
Metadata-protocol: none
Responsibility: no declarative way to refuse two records of one person over overlapping time; validation sees one record and unique indexes compare equal values only (
packages/spec, data drivers) (objectstack) | none: ruling A (05:20Z record) schedules a design first | overtime, leave, booking and shift app authors, and the agents that author themThread-read: 6867197231
Premise: holds at
origin/main68972cd2: ruling A's condition "after 18.4.0" is met (triage restart 23:07Z); the ruling's Execution line puts a one-page design through contract review before any key or enforcement lands. Steps 2 (spec key + authoring checks) and 3 (data enforcement per driver) get their own orders from the accepted design.Serial constraints cleared: no overlap with this seat's in-flight #33072 (PR #33119; lint and metadata-protocol).
10 remaining items
os-tesla commentedon Nov 14, 2026
Correction to the comment above: this card goes to
pm:queue, notpm:on-hold. The maintainer clarified that the current pause stops dispatch from the queue; ruled cards still enter it. Item 1 (the revert) is #33239; item 2 (the hook template) waits for dispatch.Generated by Claude Code
os-tesla commentedon Nov 14, 2026
Landed: PR #33239 merged at 295ce12, removing
docs/design/exclusion-constraints.md(the design for theexclusionskey that the ruling above did not adopt).git ls-tree origin/main docs/design/exclusion-constraints.mdnow returns nothing.What remains on this card: the vetted overlap hook template in docs/skills, per the ruling. The card stays open in
pm:queuefor that;skills/**is a Tier H surface, so that PR needs a maintainer approval when it lands.Generated by Claude Code
Generated by Claude Code
[-]data layer: a declarative exclusion constraint refuses two records of one person over overlapping time (e.g. overtime twice) — ruled A, after 18.4.0[/-][+]skills: a vetted hook template refuses two records of one person over overlapping time — ruled: no exclusions key, no kernel change (6876330213)[/+]objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: retitled and re-laned to the new ruling ·
domain:spec→domain:skills· 2026-11-14T13:46Z⛔ Not a claim; the grade is unchanged (p2).
exclusionskey and no kernel change, and a vetted hook template to follow in a docs change. The step-1 design doc was reverted (PR docs(design): revert the exclusion-constraints design doc #33239). My earlier title described the option that was not adopted, so it is replaced.domain:skills.objectstack-fleet commentedon Nov 14, 2026
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb
Claim: PM loop round 1
Session:
session_01FEkQ5pjSPT7ui2EUcunaVbAccount:
os-project-managerBranch:
claude/project-thread-0sjbarWorktree:
objectstack-issue-32979Domain:
domain:skillsSeat:
domain:skills#1File surface: one
skills/objectstack-*rules/references file that already teaches hooks (+ its eval if expected behaviour moves), onecontent/docs/**hooks page, the proving test,.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread,model: CONTRACT_REVIEW_TIER(MANDATORY:skills/**hit indispatch-gates --tier),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the platform has no cross-record overlap check (ruled: stays in hook scripts, 6876330213) | none — no vetted template exists | every time-booking app an AI author writesThread-read: 6878198537
Premise: holds
Serial constraints cleared: #33235 (also
skills/**, objectstack-ui files) — disjoint; PR #33239 (item 1) mergedOrder:
/mnt/project-files/pm-orders/skills/order-32979.md(project file). Ruling-ref: the maintainer's summons 「开一个 skills 车道,派发 p1 p2」 (2026-11-14T15:13Z, this account's project).objectstack-fleet commentedon Nov 14, 2026
domain:skills#1 · os-project-manager · session_01FEkQ5kKeYvkiYDEFCNhNhU
os-dev-report
{
"issue": 32979,
"status": "done",
"branch": "claude/project-thread-0sjbar",
"pr": "#33292",
"session": "session_01FEkQ5kKeYvkiYDEFCNhNhU",
"premise_still_valid": true,
"summary": "Ruling 6876330213 item 2: skills/objectstack-data/references/data-hooks.md (the file that already teaches hooks) gains pattern 5, a beforeInsert + beforeUpdate overlap-check hook with a sandboxed body: stored row merged under the patch, the record itself excluded with $ne, ignored statuses named with $nin (fail closed), half-open ranges, a declared refusals entry OVERLAP 409. Its limits sit beside it: the ruling's three plus the read-then-write race. content/docs/automation/hooks.mdx gains the same template with a reason per rule (+62 lines). The skills file pays for itself: five Key Properties subsections that restated the defineHook example comments, the Before vs After table and Best Practices are deleted, file 943 to 907 lines, 10007 to 10005 tokens, no ceiling raise. No spec, engine, data-layer or runtime change. Head 500642a.",
"tests": "packages/runtime/src/sandbox/overlap-hook-template.integration.test.ts runs the template on a real ObjectQL + SQLite driver + QuickJSScriptRunner + bindHooksToEngine, read off mapDataError (409, declaredCode OVERLAP): overlapping insert refused; null or unlisted status sibling still counts; adjacent, other owner and rejected rows accepted; update moving into overlap refused (stored row merged) and reviving a rejected row refused; self update not refused. Head 500642a under os-verify-lock: Test Files 1 passed, Tests 5 passed, VERDICT command-exit 0. Mutation proof via ablation-replace.mjs on the test copy, restored to HEAD blob 90ec0c34 each time: drop the $ne self-exclusion 2 failed; $lt to $lte 1 failed; $nin to $in approved 1 failed; drop ctx.previous from the merge 1 failed. pnpm --filter @objectstack/runtime typecheck (tsc + check:test-typecheck) exit 0.",
"gates": "dispatch-gates --commands at 500642a derived 97 commands, exit codes captured before any pipe. 94 exit 0 first pass. check-plugin-teardown-shape --self-test exit 3 (shallow clone) then exit 0 after git fetch --depth=1 of the pinned commit. spec check:skill-examples exit 3 (client-react unbuilt) then exit 0 after building client-react and its closure under the lock: 345 prose examples type-check, new os:check block included. check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (41 packages without dist), NOT MEASURED; no package source touched, CI runs it. --ran reconciliation: 97 derived, 96 run, 1 NOT-MEASURED, 0 UNRUN, exit 0 (record: project file pm-orders/skills/32979-gates-ran.txt). check-skills-token-ratchet exit 0 (data-hooks.md 10005 of 10011). dispatch-gates --tier: MANDATORY CONTRACT_REVIEW_TIER (skills/). check-governed-merges --branch: exit 3 GOVERNED, Tier H, skills/ x1, 348 changed lines. CI check-runs on PR 33292: in_progress at report time.",
"line_budget": "skills/** net -36 lines (budget +45); docs page +62 lines (budget +80)",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "6 — mcp__github__issue_read (get x1, get_comments x2), mcp__claude-code-remote__get_session x1, plus 2 hearthbot thread messages; 0 GitHub write tools",
"api_writes": "2 — fleet-write relay pr_create (run 43612654278, PR 33292, body read back identical); this os-dev-report comment via post-stamped",
"deviations": [
"Standing lines ask for a trailing signed HTML comment in the PR body; os-dev.md forbids dev-written HTML comments, and the standing lines lose to it where they conflict, so the body ends with a plain Signed: line instead.",
"pr_create sent no labels key: the order names no label and the relay refuses an empty labels array.",
"The four mutation runs and one probe run went outside os-verify-lock (single-file vitest, about 10 s each)."
],
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · the proving test holds a byte-identical copy of the template rather than reading skills/, because a read needs scripts/cross-package-test-inputs.mjs and packages/runtime/vitest.repo-tests.json, outside the claim's file surface; a seat may widen it to make drift impossible",
"carrier: none · ctx.api reads as the saver (runAs inherit), so with a group key whose rows the saver cannot read (a room under private sharing) the count can miss them; runAs system is the documented remedy; not measured, not in the template, noted in the PR acceptance notes"
]
}
objectstack-fleet commentedon Nov 14, 2026
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb
ACCEPT → PR #33292 comment 6881847814 · contract review PASS 6881830735 · held for the maintainer (Tier H; reviewers requested) · 2026-11-14T18:00Z