Repository navigation
docs(adr): ADR-0148 — the recycle bin is a separate store, restore under the original ids, retention in days (#3146 slice 1) - #30263
objectstack-fleet[bot] wants to merge 3 commits into
Conversation
…ore under the original ids, retention in days The maintainer ruled the recycle-bin shape on #3146 (ruling record 6629858351): one sys_recycle_bin entry per delete operation with the cascade set snapshotted, the delete staying physical and every read path untouched; restore under the original ids with three named refusals; retention as days (default 30, OS_RECYCLE_BIN_RETENTION_DAYS) through a host resolver hook on the resolveFeatures pattern, so the framework knows days and never plans. The record names, for every new surface, the reader that will enforce it and the card that lands it, and says the keys ADR-0049 removed stay removed. ADR-0049 gains one dated note on its Status line; its decision text is unchanged. docs/adr/README.md is regenerated by scripts/adr-index.mjs. Claude-Session: https://claude.ai/code/session_01WGufzfC3wLXmeCXwxa963a Co-authored-by: Claude <noreply@anthropic.com>
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract reviewServed-tier: ① Derived judgments
must-fix M1 — the ADR-0049 note states a fact main does not carry. 0049 L3 (new text) and ADR-0148 L39, L272-274 say the four keys' "tombstones and ADR-0087 conversions stand". At main only must-fix M2 — a mechanism decided in D1/D5 and undecided in D6. D1 L146-147 says an entry records "the retention window it was given"; D5 row 1 L263 says "the resolved window"; D6 L288-291 says whether the window is stamped at delete or resolved by the sweep is #30237's choice. The ruling decided neither. #30235 (field list) and #30237 would each read a different answer; pick one place and one wording. should-fix S1 — ② Semver levelNone. Docs only under ③ Boundary flags
④ Design judgmentThe record is faithful to 6629858351 item by item, honest about what ships (nothing) and about the ADR-0012 citation, and gives #30235 enough to build from (object name, no object-level key, days-only hook, three refusals with codes left to the ADR-0112 ledger, and D6 naming who decides the rest). The two must-fixes are drafting errors of the kind the card warns will be paid by every child: a false "conversions stand" claim written into ADR-0049's own Status line, and a retention-window field decided in D1/D5 and left open in D6. Both are one-line corrections; the should-fixes are provenance honesty (which spellings the record fixed vs the ruling fixed) and one wrong property name. Implemented-by: VERDICT: FAIL |
…deadline at delete, and reads the ADR-0087 conversions as main carries them Contract review 6649543275 on #30263 found two must-fixes and seven should-fixes, all text. This commit answers them in one change: - The claim that the old keys' ADR-0087 conversions "stand" was false: only the allowRestore / allowPurge conversion (entries/18) is still carried; the 16.x enable.trash conversion has aged out of the load path (retired in the census, no entry file) and softDelete never had one. ADR-0148's Builds on, Leaves unchanged, Context and D5 now say exactly that, and ADR-0049's Status note says the same. - The retention window is now decided once: the resolver is asked at delete and its answer is stamped on the entry as the purge deadline (D1, D3, D5, Rollout), with the reasons, and D6 no longer leaves it open. - sys_recycle_bin and OS_RECYCLE_BIN_RETENTION_DAYS were the ruling's examples; the record now says it fixes them. The hook's input, output and validation, the stamped deadline, the default datasource and "secret fields out in v1" are marked as the record's choices, listed once in a new D7. The "adds no mechanism of its own" sentence is gone. - "Empty" is an admin's verb (the ruling gives a person restore of their own deletes and an admin everything); the non-admin reading is removed. - The reference-field vocabulary is deleteBehavior, not onDelete. - The Status value is one line again; docs/adr/README.md is regenerated. - #30235's body lists the object, the hook contract and the refusal codes; the record now says it adds the restored event's name and the grant keys to that card, and moves the operation-vocabulary pin (an objectql test) to #30237. Claude-Session: https://claude.ai/code/session_01WGufzfC3wLXmeCXwxa963a Co-authored-by: Claude <noreply@anthropic.com>
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract-review-claim: session_01WGufzfgvGexKn9vLHsy89K · head 9b45718 · 2026-11-05T04:34Z Delta review of fix round 1 ( |
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract reviewServed-tier: ① Derived judgments
should-fix S8 — ADR-0049 L3 and ADR-0148 L114-115, L292 say the trash conversion "aged out of the load path" / "is retired from the load path (listed as such in the census)", against the permission conversion that "stands". ② Semver levelNone. Docs only under ③ Boundary flags
④ Design judgmentThe fix round answers every finding of 6649543275 and does so against main rather than against the review's wording: the ADR-0087 facts are read from the census and the one surviving entry, the deadline is fixed in one place with a plan-change rationale that holds in both directions, and D7 gives #30235 and #30237 a single list of what the record, not the maintainer, chose. The four should-fixes are precision residue (an ADR-0087 term that names the wrong concept, a muddled sentence, one unlisted choice, a loose analogy), none of which a child card would build wrongly on. Implemented-by: VERDICT: PASS |
…ld hold, and resolve-at-sweep as the rejected alternative Delta review 6649866889 on #30263 passed with four should-fixes, all text: - "Aged out of the load path" named the wrong concept: both conversions are retiredFromLoadPath. The difference main carries is ADR-0087's kit rule — the enable.trash kit's conversion was removed when 18 was cut (its tombstone stays), the allowRestore/allowPurge kit is carried at 18 and ages out at 19, and neither replays at load. ADR-0049's Status note and ADR-0148's Builds on, Leaves unchanged, Context and D5 now say "kit". - D4's reason for keeping secrets out of the snapshot no longer conflates the value with the ref: under ADR-0100 the row carries only the secret ref, so the snapshot would hold a ref the committed delete released, and encrypting the value into the entry would open a second store outside sys_secret. - D7 gains the two choices it omitted: no object-level authoring key (by rule, not by a flag) and the privacy rules as standing rules that bind v1 and everything after it; D5 and D4 mark them where they are made. - D3 names resolve-at-sweep (the LifecycleService's lifecycle-namespace windows, global and per tenant; the sys_file reap's deleted_at plus a static expireAfter) as the alternative the record rejects, and leaves the reap shape on the stamped column to #30237. docs/adr/README.md is unchanged by this commit (the Status lines did not move). Claude-Session: https://claude.ai/code/session_01WGufzfC3wLXmeCXwxa963a Co-authored-by: Claude <noreply@anthropic.com>
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K 维护者速读
席位意见:fable 契约复审三轮。
席位核对 — ACCEPT · domain:spec#3 · head
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Requested by Yibo Wang · project thread
Fixes #30234
Part of #3146 · Ruling-ref: 6629858351 (maintainer, 2026-11-04, 「同意,企业版功能在 cloud 中立卡后续开发」)
Clause-②: no (docs only, an ADR; the protocol addition rides #30235)
Metadata-protocol: none
Skills-docs: none — docs only and
Metadata-protocol: none; the two passages ofskills/objectstack-api/SKILL.mdthat teach "the trash surface is retired" and "there is no recycle bin" stay true until the engine slice ships, so their rewrite is owed by #30235 / #30237, not by this recordPrior rulings read: recycle bin,softdelete,trash,retention → 3 hits; ADR-0006 D1, ADR-0045 Decision §6, ADR-0131 D1; thread: none; repo: objectstack-ai/objectstack
维护者速读
docs/adr/0148-recycle-bin-separate-store-restore-under-original-ids-retention-in-days.md,把你 2026-11-04 在 Implement soft delete (recycle bin):enable.trash/softDeleteare spec-only with zero runtime readers #3146 上的裁决(回收站独立存储、每次删除一条记录、按原 id 恢复、保留期按天经宿主钩子、企业层放 cloud)记成正式 ADR;ADR-0049 的**Status**:行末尾追加一条日期注记,说明旧键保持移除;docs/adr/README.md由scripts/adr-index.mjs重新生成。无代码、无 schema、无生成产物。enable.trash/softDeleteare spec-only with zero runtime readers #3146 拆出的三张子卡(spec: declare the recycle-bin surface — the sys_recycle_bin object, the retention hook and the restore refusals (#3146 slice 2) #30235 spec、engine: snapshot deletes into the recycle bin, restore under original ids, purge, and the TTL reap (#3146 slice 3) #30237 engine、ui: the admin recycle-bin page (list, restore, empty) and the 已删除 · 撤销 toast (#3146 slice 4) #30239 UI)都要引用一份 ADR;ADR-0049 当年因无读者删掉了enable.trash/softDelete/allowRestore/allowPurge,新面必须先把未来的读者逐项点名,否则又是「声明而不执行」。IsDeleted列)、D3(天数与宿主钩子,框架只知天数不知套餐)、D5(新面 → 读者 → 承载卡的表,以及旧键保持墓碑:按 ADR-0087 的 kit 规则,allowRestore/allowPurge的 kit 在 18 仍保留、19 退出,enable.trashkit 的转换已在 18 切版时移除,两者都不在加载路径上重放)、D7(记录自己定下、裁决未定的几项选择,逐项标明);② ADR-0049 第 3 行状态行末尾的注记;③ 「Where "days, never plans" is written down」一节——仓内没有 ADR 写下这条原则,它写在resolveFeatures接缝的注释里并引用 cloud ADR-0012。pnpm check:adr-index && pnpm check:adr-links && pnpm check:adr-symbol-anchors,预期三条全绿,索引显示 149 条记录、ADR-0148 状态为 Accepted。docs/adr/**是 Tier H,需要你 Approve(或亲手合并);席位不会排队、不会开 auto-merge。What changes
docs/adr/0148-recycle-bin-separate-store-restore-under-original-ids-retention-in-days.md(427 lines). It records the ruling in the ruling's own terms; where it fixes a name the ruling offered as an example or settles something the ruling left open, it says so at that point and lists each such choice once in D7. StatusAccepted — 2026-11-05, with the sentence "This record declares; it implements nothing": nothing in it ships onmain, and every mechanism is worded as decided and planned, with its tracking card.docs/adr/0049-no-unenforced-security-properties.md: one dated amendment note appended to the end of its**Status**:line (the line still starts**Status**:; the keywordAcceptedis unmoved). The note points at ADR-0148 and says the removed keys stay removed — tombstones stand; under ADR-0087's kit rule theallowRestore/allowPurgekit (entries/18, retired after 17.2.0) is carried at 18 and ages out at 19, theenable.trashkit's conversion was removed when 18 was cut and only its tombstone remains, neither replays at load (bothretiredFromLoadPath);softDeletenever had one. The decision text is untouched.docs/adr/README.md: regenerated bynode scripts/adr-index.mjs(the index is generated, not hand-kept): 148 → 149 records, 143 → 144 numbers, one new row.Where each ruling item is recorded
deleted_atcolumn; one entry per delete operation; the cascade set snapshotted; the delete stays physical; every read path untouched; why not Salesforce'sIsDeletedcreated_by/created_atkept; its own restored event, never a create; the three refusals (unique taken, parent purged, package uninstalled); lookup re-link only when unchanged since; flow enrollments not restored; rollups recompute; a cascaded child not restored alone; a person restores what they deleted, an admin sees allOS_RECYCLE_BIN_RETENTION_DAYS; a host resolver hook on theresolveFeaturespattern; days, never plans; TTL purge on the LifecycleService following thesys_filetombstone; permanent delete never enters the binsys_recycle_binandOS_RECYCLE_BIN_RETENTION_DAYS; the hook's input, output and validation; the purge deadline stamped on the entry at delete time; the entry stored by the default datasource; secret fields out of the snapshot in v1; therestoredevent's name and the grant keys added to #30235's scope; no object-level authoring key (by rule, not by a flag); the privacy rules as standing rules that bind v1 and everything after itMeasurements this record is built on
main(bb86ff9) ends at ADR-0147. Every one of the 34 open PRs was read for adocs/adr/01NN-*.mdit adds — docs(adr): under a walled tenancy posture every external object states its organization scope (ADR-0015 §10) #29866 (the one opendocs(adr)PR) amends ADR-0015 and adds no record; the 17 other non-mailbox PRs, the 15 mailbox PRs and the Version Packages PR add none (each head'sdocs/adr/tree listed). 0148 is free.enable.trashandsoftDeleteremoved in the 16.x line ([11.0][A2] Remove dead author-facing metadata properties (ADR-0049 enforce-or-remove) #2377;packages/spec/src/data/object.zod.ts, which still says "there is no soft-delete/recycle-bin runtime … Deletes are hard deletes");allowRestore/allowPurgeremoved with spec: retire theallowRestore/allowPurgepermission props (ruled 2026-08-26; M2 anchor stays open, keys return with M2) #12497 (the permission-schema tombstone says@objectstack/spec17, the conversion entrypermission-allow-restore-purge-removed.tssays protocol 18; the ADR cites the card number and not a version). The card's "removed in 16.0" is therefore exact for two of the four keys; the record reads the code.docs/adr/states it (grep forresolveFeatures, "plan-agnostic", "plan name": zero hits). This repository's ADR-0012 is the messaging platform. The principle is written in the docblock ofpackages/cloud-connection/src/runtime-config-plugin.ts("Feature seam (open-core boundary — cloud ADR-0012)": the open package owns the mechanism; which billing plan unlocks a key is a distribution concern never enumerated in the framework; hosts inject throughresolveFeatures, which takes an opaque token — cloud passes the plan string — and returns an open-ended map merged verbatim) and in the package's 9.5.0 changelog entry ("plan-agnostic"). The nearest ADR here is ADR-0132 D2. So the ruling's "ADR-0012" is cloud ADR-0012; the record says so in its Provenance and in a section of its own, and cites it as Prime Directive [WIP] Add Chinese version of the documentation #13 spells a cloud record.packages/objectql/src/engine-delete-cascade.ts(collectCascadeDeleteSet,refuseRestrictsInsideOwnCascade),packages/services/service-storage/src/attachment-lifecycle.tsandpackages/services/service-storage/src/objects/system-file.object.ts(thesys_filetombstone and its 30-day reap),packages/objectql/src/lifecycle/lifecycle-service.ts(LifecycleService),packages/objectql/src/engine-secret-internal-fields.ts(releaseSecretHandles, objectql: deleting a record does not release the sys_secret row its secret field names #27581),packages/plugins/plugin-security/src/permission-evaluator.ts(DESTRUCTIVE_OPERATIONS,OPERATION_TO_PERMISSION). No line anchors.Why
The maintainer unparked #3146 on 2026-11-04 with the recycle-bin shape, and triage split it into four children chained by
Blocked-by:; this card is the first, and the p1 spec card #30235 cannot start without a record to cite. ADR-0049 removed the earlier soft-delete keys because nothing read them; a new surface under the same policy has to name its readers before it is declared, which is what D5 does.Verification
node scripts/pm/check-prior-rulings.mjs --card 30234 --terms "recycle bin,softDelete,trash,retention"— thePrior rulings read:line above. The three ADR hits are on other senses of the terms (ADR-0006 D1 keeps the wordproject; ADR-0045 §6 is the unpublished-build trash-can discard, which ADR-0148 names as a different surface; ADR-0131 D1 is NULL organization ids). None rules on the recycle bin.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, change set derived from the merge base bb86ff9 oforigin/main): 21 commands, run serially at head 0d59704 (the second review-fix commit; the same 21 ran at b28128a and 9b45718 with the same codes); the readings are in the details block below and reconciled with--ran(21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN).docs/adr/**is Tier H (Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14): this PR stays a draft; the seat reviews and ACCEPTs, and the maintainer lands it by hand. No automerge is armed and none will be.Derived gates at 0d59704 — 21 commands, every exit code 0 (recorded before any pipe; reconciled: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN)
Verdict lines of the three ADR gates, quoted from their own output:
check:doc-formula-expressionsran after its prerequisite build (turbo run build --filter=@objectstack/formula --filter=@objectstack/lintunderos-verify-lock.sh, VERDICT command-exit 0; 97 s held at b28128a, 5 s at 9b45718 where turbo's cache restored the two dists, which 0d59704 reused unchanged).pnpm lint(the repo-wide eslint) is CI's run and was not run locally.Acceptance notes
enable.trash/softDeleteare spec-only with zero runtime readers #3146's body citesdocs/audits/2026-06-objectschema-property-liveness.md, which is not onmain(the June 2026 sheets present areappschema,security-identity,validationschemaandrecord-search). ADR-0148 cites the audit by its card ([P0] Metadata property liveness audit: ~half of all spec properties are dead; a cluster of security props is parsed-but-unenforced #1878) and thedocs/audits/directory instead of the missing path. A dead citation in an issue body is not one of the three carded classes.allowRestore/allowPurgeto spec: retire theallowRestore/allowPurgepermission props (ruled 2026-08-26; M2 anchor stays open, keys return with M2) #12497 (spec 17 / protocol 18). The record reads the tombstones. No metadata author is misled: both spellings are refused with the same prescription.skills/objectstack-api/SKILL.mdteaches "the trash surface is retired" and "there is no recycle bin". Both stay true until engine: snapshot deletes into the recycle bin, restore under original ids, purge, and the TTL reap (#3146 slice 3) #30237 ships; the rewrite rides spec: declare the recycle-bin surface — the sys_recycle_bin object, the retention hook and the restore refusals (#3146 slice 2) #30235 / engine: snapshot deletes into the recycle bin, restore under original ids, purge, and the TTL reap (#3146 slice 3) #30237 under their ownSkills-docs:lines.Co-Authored-Bytrailer; the commit carries the repository's model-free pair (Co-authored-by: Claude+Claude-Session:), which the pre-push hook requires..claude/agents/os-dev.mdrule 2 keeps the PR's people with the seat at hand-over, andpr_createwent out with no assignees and no reviewers.Human Minimum
packages/specholds no runtime logic. (No schema moved.)sys_recycle_bin,OS_RECYCLE_BIN_RETENTION_DAYS— named in prose only.)pnpm lintis CI's run (docs only; no.tsmoved).main(the harness-pinned card-thread branch, atmain's bb86ff9), one pull request.docs/adr/**only), labelskip-changeset; both declaration lines are above.packages/spectouched: no.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzfC3wLXmeCXwxa963a