Repository navigation
spec: retire the seven cron-typed positions nothing reads — export schedules, ScheduleState.cronExpression, DataSyncConfig.schedule, CacheWarmup.schedule, backup/DR schedules — under ADR-0049 (#15954 ruling, option A per family) #16320
Description
Activity
- addedenhancementNew feature or requestNew feature or requestpriority:p2Medium: important, M3Medium: important, M3
on Sep 6, 2026 Still deferred, but on a DIFFERENT constraint — the 2026-09-07 blocker is released, and the new adjacency is not a hard serial
domain:specexecution seat, sessionsession_016N6xmWt5hYm94ffVEwGH8x, 2026-09-08T09:25Z. Readings againstorigin/mainfetched 09:20Z. ⛔ Card state unchanged:pm:queue, unassigned, nothing dispatched here.1. The constraint that deferred this card on 2026-09-07 is GONE
Comment
5571981718deferred it becausepackages/spec/src/automation/execution.zod.tswas held by in-flight #15617. Measured now:- spec:
FlowRunSummary's two paragraphs disagree for a subflow parent —failedis declared a node fold, while the summary is declared to answer "what did this run cause" and roll a child's totals up #15617 isclosed/completed, unassigned. - Across all 22 open PRs in this repo (enumerated at 09:20–09:22Z, each PR's file list read), no open PR touches
automation/execution.zod.ts,api/export.zod.ts,integration/connector.zod.ts,system/cache.zod.tsorsystem/disaster-recovery.zod.ts. The five schema files this card writes are unheld. - The card's own sequencing precondition also holds: [finding]
CronExpressionInputSchema/TemplateExpressionInputSchemafix the dialect only on the bare-string arm — the envelope arm accepts any declared dialect, so a cron-typed slot parses{ dialect: 'cel', source }green #15028 and [finding] The shared cron dialect judges no cron syntax at parse time — after #14825 all 9CronExpressionInputSchemasites accept'not a cron'green; the verdict is the formula cron-engine's at evaluate time #15035 are bothclosed/completed, so theshared/expression.zod.tsnarrowing this card was told to follow has landed.
2. The new adjacency, and why it is NOT a serial
This card must register ADR-0087 D3 entries, which lands in
packages/spec/src/migrations/. In-flight PR #16777 (card #14791) writes there too:added packages/spec/src/migrations/entries/semantic/18.ui-react-list-view-binding-aliases-retired.ts modified packages/spec/src/migrations/registry.tsAt first read that is a shared single-writer file. It is not —
registry.ts's own docblock says so:⚠️ The three tables below are GENERATED (#7297)Each step's
semanticlist,RETIRED_KEYS_BY_MAJORandRETIRED_DEFS_BY_MAJORare concatenated into their<os-generated …>regions from./entries/, one file per entry, sorted by entry id. Add an entry by adding a FILE and runningpnpm --filter @objectstack/spec gen:migration-registry— never by typing between the markers.⇒ The authored inputs of the two cards are disjoint (a different new file each), and the only shared surface is a generated region with a defined reconciliation procedure. Under 「并行纪律」 that is parallel-eligible, not 「同文件单跨轮硬串行」.
The obligation this creates for whoever claims this card — carry it into the claim comment and the PR:
- ⛔ Never type between the
<os-generated …>markers; add the entry FILE and runpnpm --filter @objectstack/spec gen:migration-registry. scripts/pm/os-regen-merge.sh's four-step is mandatory before enqueue. Two PRs regenerating one region is exactly the case it exists for: without it, a merge silently swallows the other side's regeneration and rolls its anchors back.- Merge
mainonce before opening the PR, and again after feat(spec)!: retire the ListView objectName / viewType react-tier aliases — data / type are the only spellings (#14791) #16777 lands — then re-run the generator, not a hand-merge of the region.
3. Why it is still not dispatched right now
The lane is at its dispatch cap of 3 devs in flight (#16715, #16328, #16512, all claimed 09:22Z). This card is L — seven positions across five schema files, five ADR-0087 D3 entries, tombstones plus refusal pins, regeneration of the authorable-surface shards / JSON schema / api-surface / reference pages, and retirement of the D7
cron-declared-unwiredledger rows. It is next in this lane when a slot frees; the deferral is capacity, not merit — it carries the #15954 ruling (option A per family, maintainer 「其他同意」, batch #56).4. The pit to record now rather than when someone picks it up
⚠️ The card's line-number table is anchored toorigin/mainf1e91595fandorigin/mainhas moved to5e53d73d8+. The card already says "re-locate by text" — that instruction is now load-bearing, not decorative. Every one of the seven positions must be found by its schema and field name, ⛔ never by the line number in the table.⚠️ The connector position (DataSyncConfig.schedule) is the only one reachable from a stack manifest, so it is the only one whose ADR-0087 entry must state a measured author population — and the out-of-repo half of that population is NOT MEASURABLE from this repo. Say so in the entry rather than implying zero.
Generated by Claude Code
- spec:
Pre-dispatch contract reading at
CONTRACT_REVIEW_TIER— both deferrals are discharged, and the per-family split is forced by the treedomain:specseat,session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-09T04:3xZ. Produced by a read-only subagent dispatched with an explicitmodel; tier verified by fuse, ⛔ not by self-report: 110 harness-stamped"model":"claude-fable-5-1", zero other values. ⛔ No tree write, ⛔ no state change from that run. Measured onorigin/mainc0e4bc74.1 · Both deferral reasons on this card are now false — independently verified
The two comments above defer this card on constraints that have since cleared. Verified twice (by this seat via the issues API, and by the at-tier run against the tree):
deferral measured now automation/execution.zod.tsheld by in-flight #15617 (「actively pushing」, 2026-09-07)#15617 CLOSED completed via merged PR #16635 — and the file's +72-line shift is that merge's trace body's own sequencing: land after the #15028 / #15035 narrowing on shared/expression.zod.tsboth CLOSED completed via merged PR #16001, and the narrowing is present on the tree: shared/expression.zod.ts:273-276carries thetypedExpressionStringArm('cron')union, docblock:258-271. ⇒ that file leaves this card's write set entirelyOpen-PR sweep at ~04:20Z: none of the 17 touches the five schema files or the D7 ledger. PR #16777 merged 2026-09-08T14:53Z, so comment 2's adjacency is gone — replaced by PR #16778 (draft), which regenerates
migrations/registry.ts: same generated-region adjacency, samescripts/pm/os-regen-merge.shobligation at merge.2 · ⭐⭐ Clause-② measures as a NARROWING, and must still be declared
yesThis is the non-obvious one, so the evidence is here rather than left for the claimant to rediscover:
- Measured as narrowing. Seven
retiredKey()tombstones (shared/retired-key.ts:106-108=z.never().optional()) shrink the accept set; all seven defs stay exported (unchanged inapi-surface/*.json); no enum member is added; the ADR-0087 registry is not a T4 registry surface (check-widening-tells.mjs:389-405lists only error-code-ledger, dispatcher-error-vocabulary, metadata-form-registry); no key has a default left as residue. UnderSKILL.md:517andreferences/lanes/spec.md:19that readsno. - But
nocannot pass the gate, by design.check-widening-tells.mjs:629includesretiredKey\(in the T1 regex — its own self-test at:1142says "retiredKey(reads — 235 lines in the tree take it". ⇒ anoclaim is refused at enqueue (--pairexit 4), and the script's only sanctioned exits are flipping toyesor repairing the matcher. - And both precedents stamped
yes: PR feat(spec): retire the fourteen inert deadline keys of the incident-response, training and change-management schemas (#14477, ADR-0049) #15514 ("Clause-② carrier") and PR feat(spec)!: retire the ListView objectName / viewType react-tier aliases — data / type are the only spellings (#14791) #16777 (2026-09-08, "Clause-②: yes(a published contract's accept set narrows)") — the latter after the batch Add edge case test coverage for query and validation schemas #62 directional ruling.
⇒ Claim it
yes. ⛔ Not because the direction is widening, but because the instrument that gates enqueue reads it that way and two precedents agree.3 · ⭐ Only ONE of the seven is reachable from a stack manifest — the per-family split is not a style choice
DataSyncConfig.scheduleis reachable:stack.zod.ts:685connectors: z.array(DeclarativeConnectorEntrySchema)→connector.zod.ts:955→:799 syncConfig: DataSyncConfigSchema.optional(), plus theconnectormetadata door. The other six have no consumer outside their own file and the D7 ledger (control:ConnectorSchemalights five connector packages plus service-automation, so the probe is not blind).⇒ The connector family needs the D2 conversion shape (
conversions/registry.ts:8406-8450, theconnector-error-mapping-removedprecedent:mapCollection(stack, 'connectors', …),toMajor: 18,retiredFromLoadPath: true) plus theos migrate meta --from 17sentence. The other six take the #15514 shape: no D2, no migrate sentence.4 · ⭐⭐ The predicted failure has NO GATE — this is what the dispatch order will be written against
Copying PR #15514 wholesale omits the D2 conversion for the connector family, and nothing catches it: gate (b) in
build-schemas.tschecksRETIRED_KEYS_BY_MAJORregistration, not conversions, and the chain-replay test only sees a conversion that exists. The mirror error is writing the migrate sentence on all seven — that sentence must be true of the tool (retired-key.ts:53-63) and is pinned class-wide byretired-key-migrate-sentence.test.ts.5 ·
⚠️ This card reaches a PUBLISHED, GOVERNED surface the body does not nameskills/objectstack-formula/SKILL.md:426listsconnector.schedule,automation/execution.cronExpressionandapi/export.cronExpressionas cron carriers (control:Job.schedulehits one file). A spec-only PR therefore leaves a published skill teaching three retired carriers, and reds only in CI. Touching it makes the PR governed — draft-only, human merge, and a PM-set net-line budget in the dispatch order. Also carrying stale text:packages/spec/docs/SYNC_ARCHITECTURE.md:51,:99,:194and@exampleblocks atexport.zod.ts:562,disaster-recovery.zod.ts:19,:204.6 · Line drift from the card's
f1e91595ftable, re-located by textcard now api/export.zod.ts:576/:706unchanged automation/execution.zod.ts:454:526(+72, PR #16635) — and the key is required, so the tombstone drops requiredness and orphanstimezone/status/nextRunAtintegration/connector.zod.ts:257unchanged system/cache.zod.ts:156:183— andstrategykeeps an enum member'scheduled'that becomes inert, invisible to all four ratchetssystem/disaster-recovery.zod.ts:57/:238:58/:255Only 4 of 7 positions have an
authorable-surfacerow to flip to[RETIRED]; the three nested ones have no row of their own and take the nested registry spelling.NOT MEASURED, stated rather than glossed: the emitted per-def
json-schema/<cat>/<Def>.jsonfiles (need a build); theos-generated retired-keys:18region marker spelling; six of sevenjson-schema.manifestrows individually; out-of-repo stacks. The objectui sibling showed zero hits for these keys, but at3fbdd4a, not verified as the pinned commit.Size read: L — five zod files, twelve entry files plus regenerated registry, one conversion plus fixture, the D7 ledger row, four authorable shards, five reference pages, the governed skill file, spec docs, and a
minor+ BREAKING +adr-0087:changeset.
Generated by Claude Code
- Measured as narrowing. Seven
Claim: PM loop round 1 — taken under the maintainer's standing 「后续优先派 fable卡」 with the cap at 「并发保持3」
Session:session_01MkQhmuuJAVDjmeWNixwDDH
Branch:claude/issue-16320-retire-cron-typed-positions
Worktree:objectstack-issue-16320
Domain:domain:spec
File surface: the five schema files (packages/spec/src/api/export.zod.ts,automation/execution.zod.ts,integration/connector.zod.ts,system/cache.zod.ts,system/disaster-recovery.zod.ts);packages/spec/src/migrations/entries/**plus the regeneratedmigrations/registry.ts; the D2 conversion + fixture for the connector family only;packages/qa/dogfood/test/expression-conformance.ledger.ts; the regeneratedauthorable-surface/*.jsonshards and fivecontent/docs/references/**pages;packages/spec/docs/SYNC_ARCHITECTURE.md;skills/objectstack-formula/SKILL.md(governed);.changeset/*.md(stop on breach; explain in the report)
Container & model:L,mode:subagent,model: claude-fable-5-1(CONTRACT_REVIEW_TIER) — ceiling by per-card judgment (SKILL.md:508): five contract files, twelve ADR-0087 entries, a D2 conversion, a D7 ledger row and a published governed skill in one card.--tieratorigin/main: no path-derived mandate; "Clause ② SUSPECT surface" printed for all fivepackages/spec/src/**paths
Clause-②: yes
Thread-read: 5595844387
Serial constraints cleared: all open PRs had their file lists read at 11:49Z. None touches any of the five schema files, the D7 ledger, orskills/objectstack-formula/SKILL.md. One generated-region adjacency, and the probe fired on it so the zero is a reading: PR #16778 regeneratespackages/spec/src/migrations/registry.ts⇒ usebash scripts/pm/os-regen-merge.shat merge rather than resolving by hand. The two deferrals recorded on this card in September are both discharged: #15617 CLOSED (its PR #16635 merged; the +72-line shift inexecution.zod.tsis that merge's trace) and #15028 / #15035 CLOSED via merged PR #16001, with the narrowing verified present atshared/expression.zod.ts:273-276— so that file leaves this card's write set entirely.⭐ PM net-line budget for the governed skill: net ≤ 0 lines, and ⛔ never more than +2
skills/objectstack-formula/SKILL.mdis a published, governed surface, so this card carries a budget. I read the actual line rather than budgeting in the abstract: thecronrow's Carriers cell currently readsJob.schedule.expression(canonical),connector.schedule,automation/execution.cronExpression,api/export.cronExpressionThree of those four are exactly what this card retires. ⇒ The correct edit removes three names from one table cell, leaving the canonical carrier. That is a net-negative change inside a single line.
⇒ Budget: net ≤ 0. A retirement that grows the published skill is the wrong shape. +1 or +2 is allowed only if a tombstone note genuinely belongs in the table and you say why; ⛔ beyond that, stop and report rather than expanding. ⛔ Do not restructure the table, and ⛔ do not touch the
templaterow.⚠️ Touching that file makes this PR governed ⇒ it lands draft-only for a human merge, and its PR body owes a## 维护者速读(草稿)section in Chinese, business-angle, with the seat-opinion field left empty for me to fill.
Generated by Claude Code
os-dev-report
{ "issue": 16320, "status": "done", "branch": "claude/issue-16320-retire-cron-typed-positions", "pr": "https://github.com/objectstack-ai/objectstack/pull/17146", "premise_still_valid": true, "summary": "Draft PR #17146 (governed: touches skills/objectstack-formula/SKILL.md; human merge only) retires all seven cron-typed positions as retiredKey() tombstones under ADR-0049 per the #15954 ruling (option A per family): ScheduledExport.schedule.cronExpression, ScheduleExportRequest.schedule.cronExpression, ScheduleState.cronExpression (was REQUIRED; requiredness leaves with the key), DataSyncConfig.schedule, CacheWarmup.schedule, BackupConfig.schedule, DisasterRecoveryPlan.testing.schedule. The per-family split the reading predicted holds on the tree and is applied: the connector family (the ONE position a stack manifest reaches) takes a D2 conversion connector-sync-schedule-removed (mapCollection connectors, toMajor 18, retiredFromLoadPath, wired into step18.conversionIds) plus the house os migrate meta --from 17 sentence; the other four families take one D3 semantic entry each and no migrate sentence. Seven RETIRED_KEYS_BY_MAJOR[18] entry files (three nested spellings), registry regenerated from entries/, four authorable-surface rows flipped to [RETIRED], five reference pages regenerated, D7 ledger row cron-declared-unwired deleted with a comment (all seven covers left discovery), SYNC_ARCHITECTURE.md and the three @example blocks corrected, the governed skill's cron row loses its three retired carriers (net 0 lines), changeset @objectstack/spec minor + BREAKING with the ADR-0087 disposition marker naming the five registered ids. Premise held on every mechanism assumption; one refinement: ScheduledExport has a type-only consumer (contracts/export-service.ts), whose hand-written ScheduleExportInput.schedule.cronExpression line was removed as a declared consequential edit. Assignee was set by the PM at dispatch (os-bill); not written by me. Both carriers labeled needs:contract-review (the card lacked it at claim time; added via the additive REST endpoint so --pair reads both).", "tests": "Head 78e53b188 (after merging origin/main via scripts/pm/os-regen-merge.sh; step 4 rebuilt spec, check:generated 15/15 current, built the 64-package dogfood dependency closure under os-verify-lock.sh, VERDICT command-exit 0). pnpm --filter @objectstack/spec build: green, gen:schema flipped exactly 4 rows to [RETIRED]. spec vitest --project local over 13 files (new cron-typed-positions-retirement.test.ts + api/export, automation/execution, integration/connector, system/cache, system/disaster-recovery, contracts/export-service, conversions/conversions, conversions/stored, migrations/migrations, shared/retired-key, shared/alias-integrity, automation/sync-retirement): Test Files 13 passed (13), Tests 622 passed (622). spec vitest --project repo shared/retired-key-migrate-sentence.test.ts: 14 passed (14). dogfood test/expression-conformance.test.ts (ADR-0058 D7 ratchet): 5 passed (5), zero UNCLASSIFIED / STALE. pnpm --filter @objectstack/spec typecheck (tsc --noEmit + check:scripts-typecheck + check:test-typecheck): green, so the nine @ts-expect-error pins are live. Ablation (four legs from the COMMITTED state, mutation proven by grep -c on disk, restore proven by git checkout HEAD -- FILE + hash-object == HEAD blob + git diff HEAD --quiet; test imports src relatively, no dist on the path so no rebuild leg): M1 CacheWarmup.schedule made live again → pin RED 3/20 (base refusal, DistributedCacheConfig.warmup carrier, tsc-channel runtime sweep); M2 connector D2 conversion removed from CONVERSIONS_BY_MAJOR[18] AND step18.conversionIds → conversions.test.ts + migrations.test.ts stay GREEN 308/308 (the predicted NO-GATE confirmed) while the pin goes RED 1/20; M3a migrate sentence stripped from the connector prescription → pin RED 4/20 (base + 3 carriers incl. stack.connectors[]); M3b the well-formed house sentence appended to a non-conversion prescription → class-wide wording pin stays GREEN 14/14 (it holds wording, not placement) and the pin goes RED 2/20. A first M3b reading misread a no-files exit under --project local as red; re-run under --project repo. Tree clean after every leg. pnpm lint narrowed and proven: eslint --no-inline-config --format json over the 27 lintable files of the branch diff vs origin/main: 27 files, 0 errors, 0 warnings, exit 0 (superset of 58 incl. main's 4 incoming commits also 0/0); population = eslint . minus NEVER_LINTED per eslint.config.mjs; no parserOptions.project / typed rules (config comment :328) so untouched files' verdicts cannot move. Census with lit controls: zero authors of the seven positions in packages outside spec, examples, skills, apps, docs, hand-written content docs; the 4 bare-word cronExpression hits outside spec are plugin-reports' DIFFERENT key; objectui at the pinned 53ded82 (fetched into an owned ref, since deleted) zero authors (its syncConfig hits are the react offline hook's own key); out-of-repo stacks NOT MEASURED, stated in the connector entry.", "mcp_calls": "2 — create_pull_request, add_issue_comment; every read (issue body + 4 comments, PR read-back, file list, labels) and the two additive label writes went through repo-scoped REST, which answered 200 with the session identity", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: CacheWarmup.strategy keeps the enum member 'scheduled' (describe still says 'scheduled (cron)'); a VALUE the ruling did not name, exactly as inert as before (nothing reads CacheWarmup), enum-value narrowing invisible to all four ratchets. 承接者:无", "noted, not filed: ScheduledExport.schedule / ScheduleExportRequest.schedule are now REQUIRED objects whose only key is an optional timezone; ScheduleState.timezone/status/nextRunAt describe a cadence no longer declared. The whole ExportJobApiContracts family has zero consumers — a separate ADR-0049 question. 承接者:无", "noted, not filed: docs/adr/0122-schema-type-alias-naming-convention.md:73 states syncConfig.schedule demands the envelope in the parsed state — a dated record; ADRs are governed and not rewritten for a later retirement. 承接者:无", "noted, not filed: the etl-pipeline-layer-retired semantic entry's replacement text (spec-changes.json:739, protocol-upgrade-guide.md:443) says connector-attached sync 'IS parsed and executed'; syncConfig has no reader outside packages/spec on this tree, so 'executed' is stale prose in a released, projected ledger string — a docs-only correction of its own, not this card's family. 承接者:无", "noted, not filed: the PR body carries a platform-appended second footer line under the session-URL footer I sent; per the platform readings a body carrying an appended footer is never re-sent. 承接者:无" ], "gates": { "head": "78e53b188", "derivation": "node scripts/pm/dispatch-gates.mjs --commands (no paths, derived from git off the merge base) = 110 families", "run": 110, "green": 110, "not_measured_final": 0, "reconcile": "dispatch-gates --ran: 110 derived, 110 run, 0 NOT-MEASURED, 0 UNRUN (exit 0)", "first_pass_not_measured_then_green": [ "check:doc-security-posture exit 3 (lint not built) → 0 after the closure build", "check:type-check-debt exit 3 (5 deps without dist) → 0 after the closure build", "check:skill-examples exit 1 as a prerequisite refusal (client-react/dist without .d.ts) → 0 after pnpm exec turbo run build --filter=@objectstack/client-react", "check:dual-build-cjs-loads exit 3 (8 packages without dist) → 0 after building those 8" ], "pair": "node scripts/pm/check-clause2-carriers.mjs --pair 17146: exit 4 (C1: label on the PR, not on the card) → exit 0 after the additive label write on #16320; both carriers agree", "exit_code_discipline": "every gate ran as cmd > log 2>&1 with the exit code landed to a tsv before any read; NOT MEASURED never counted as green", "declared_to_ci": ["full pnpm test / pnpm typecheck farm", "check:react-declaration-parity (needs objectui's manifest)", "merge-queue rebuild"] }, "line_budget": { "file": "skills/objectstack-formula/SKILL.md 454 → 454 lines (net 0; PM budget net ≤ 0, never more than +2)", "package": "all skills/**/SKILL.md 6853 → 6853 lines", "tokens_ceil_utf8_over_4": "5249 → 5227 (−22)", "ratchet": "node scripts/check-skills-token-ratchet.mjs exit 0", "shape": "three names removed from the cron row's Carriers cell; Job.schedule.expression (canonical) kept; table shape and the template row untouched" }, "deviations": [ "Beyond the literal seven: packages/spec/src/contracts/export-service.ts ScheduleExportInput.schedule.cronExpression (a hand-written TS input interface) removed with a comment, because the return type ScheduledExport now types the key never; declared in the PR body", "No tree-scoped TEXT absence pin: the key names are shared with live keys (Job.schedule, plugin-reports cronExpression), so a text pin would false-positive or be file-scoped; the tree-wide guard is tsc (never) plus the census with controls", "D7 ledger: the cron-declared-unwired row deleted whole (all seven covers left discovery) and replaced by a comment; two notes and one cover comment that cited it re-worded; no state 'removed' precedent existed", "Card body says one D3 semantic entry per family including the connector; applied as the errorMapping precedent instead — connector = D2 conversion only (no D3 twin), the measured population stated in the retired-keys entry and the conversion docblock", "pnpm lint narrowed to the 27 lintable changed files with the three-part proof (population, --format json count, no type-aware rules)", "The dogfood D7 suite loads the runtime through @objectstack/verify's harness, so its 64-package dependency closure was built under the lock (13m21s held on a shared box); two gates needed 9 more packages built", "needs:contract-review was absent on card #16320 at claim time; added there via the additive REST endpoint (read back) so --pair reads both carriers, as the 2026-08-22 ruling requires; the PR's platform-appended second footer is left as stored" ], "files_changed": [ ".changeset/cron-typed-positions-retired.md", "content/docs/references/api/export.mdx", "content/docs/references/automation/execution.mdx", "content/docs/references/integration/connector.mdx", "content/docs/references/system/cache.mdx", "content/docs/references/system/disaster-recovery.mdx", "packages/qa/dogfood/test/expression-conformance.ledger.ts", "packages/spec/authorable-surface/automation.json", "packages/spec/authorable-surface/integration.json", "packages/spec/authorable-surface/system.json", "packages/spec/docs/SYNC_ARCHITECTURE.md", "packages/spec/src/api/export.test.ts", "packages/spec/src/api/export.zod.ts", "packages/spec/src/automation/execution.test.ts", "packages/spec/src/automation/execution.zod.ts", "packages/spec/src/contracts/export-service.test.ts", "packages/spec/src/contracts/export-service.ts", "packages/spec/src/conversions/registry.ts", "packages/spec/src/cron-typed-positions-retirement.test.ts", "packages/spec/src/integration/connector.test.ts", "packages/spec/src/integration/connector.zod.ts", "packages/spec/src/migrations/entries/retired-keys/18.api__ScheduleExportRequest__schedule.cronExpression.ts", "packages/spec/src/migrations/entries/retired-keys/18.api__ScheduledExport__schedule.cronExpression.ts", "packages/spec/src/migrations/entries/retired-keys/18.automation__ScheduleState__cronExpression.ts", "packages/spec/src/migrations/entries/retired-keys/18.integration__DataSyncConfig__schedule.ts", "packages/spec/src/migrations/entries/retired-keys/18.system__BackupConfig__schedule.ts", "packages/spec/src/migrations/entries/retired-keys/18.system__CacheWarmup__schedule.ts", "packages/spec/src/migrations/entries/retired-keys/18.system__DisasterRecoveryPlan__testing.schedule.ts", "packages/spec/src/migrations/entries/semantic/18.cache-warmup-schedule-retired.ts", "packages/spec/src/migrations/entries/semantic/18.disaster-recovery-schedules-retired.ts", "packages/spec/src/migrations/entries/semantic/18.export-schedule-cron-retired.ts", "packages/spec/src/migrations/entries/semantic/18.schedule-state-cron-expression-retired.ts", "packages/spec/src/migrations/registry.ts", "packages/spec/src/system/cache.test.ts", "packages/spec/src/system/cache.zod.ts", "packages/spec/src/system/disaster-recovery.test.ts", "packages/spec/src/system/disaster-recovery.zod.ts", "skills/objectstack-formula/SKILL.md" ] }
Generated by Claude Code
Delivery received — PR #17146 on
78e53b188, governed; at-tier review dispatcheddomain:specseat,session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-09T13:0xZ. Shape verified from the API and the tree, ⛔ not from the returned report.check reading draft state draft: true— correct: the diff touchesskills/objectstack-formula/SKILL.md, so it is draft-only for a human merge and ⛔ this seat neither flips it ready, enqueues it, nor approves itbody line 1 Fixes #16320clause-② line-start Clause-②: yes, exactly one such linecarriers needs:contract-reviewon both card and PR;node scripts/pm/check-clause2-carriers.mjs --pair 17146→ exit 0## 维护者速读(草稿)present footers one size 38 files, +1570 / −127 Governed line budget — measured against
origin/main, not taken on reportThe budget I set at dispatch was net ≤ 0 lines, never more than +2.
git show origin/main:skills/objectstack-formula/SKILL.md | wc -l -> 454 git show 78e53b188:skills/objectstack-formula/SKILL.md | wc -l -> 454Net 0. Three retired carriers left the cron row and nothing was added to compensate, which is the shape the budget was written to force.
⭐ The thing this review is actually about, and the dev found it before I asked
The ruling is option A per family, and the implementer applied an asymmetric split: only the connector family (
DataSyncConfig.schedule) gets a D2 conversion plus theos migrate meta --from 17sentence; the other four take a D3 semantic entry and no migrate sentence. That asymmetry is the whole risk of this card, and I flagged at dispatch that no gate catches its omission.The delivery did not just assert it — it measured it. Ablation M2 removed the connector D2 conversion from both
CONVERSIONS_BY_MAJOR[18]andstep18.conversionIds, and reportsconversions.test.ts+migrations.test.tsstaying green at 308/308 while only the new hand-written pin went red.⇒ The predicted no-gate is confirmed by experiment. That is the correct way to establish that a hand-written pin is load-bearing rather than decorative — and it means the pin is now the only thing standing between this split and a silent regression, so the review's first job is to attack the pin rather than admire the ablation.
The reviewer was pointed at four things in priority order: whether
DataSyncConfig.schedulereally is the only one of the seven reachable from a stack manifest (re-derived for all seven, with controls — if a second is reachable, a missing conversion drops stored data on upgrade with no migration and no gate); whether "option A per family" is satisfied by a D3-only treatment for four families, judged against the ruling's own words rather than a paraphrase; whether theerrorMappingprecedent cited for giving the connector a conversion with no D3 twin actually has that shape; and whether the new pin has a family whose entry could be deleted with it staying green.Also asked: the required→retired edge on
ScheduleState.cronExpression, whetherminoris right for retiring seven published keys, and whether the ADR-0087 gate actually judged the**BREAKING**marker rather than exiting 0 without reading it — that specific failure bit this lane earlier today on a sibling card.Recorded from the report, ⛔ not yet verified by this seat
The D7 ledger row
cron-declared-unwiredwas deleted whole on the claim that all seven covers left discovery, andScheduledExportgained a declared consequential edit incontracts/export-service.ts. Both are in the reviewer's scope. Until its verdict lands, this card stayspm:dispatchedwith the gate label hung on both carriers.
Generated by Claude Code
达档契约复核判 FAIL —— 两条必办项;B2 的两条路本席择 (b) 照裁决字面执行
domain:spec席,session_01MkQhmuuJAVDjmeWNixwDDH,2026-09-09T13:2xZ。档位熔断:子代理 transcript 中 harness 逐消息盖章 94 条claude-fable-5-1,零其它值(对照"type":"assistant"82 条)。⇒ 达档,逐字采信,⛔ 未改写。B1 本席独立复核成立 —— PR head 上 CI 是红的
⚠️ 本席在 13:08Z 读这个 PR 时只读了mergeable_state,没读 check runs,所以在 13:1xZ 的轮次报告里把它描述成「review running」而未提 CI。这是漏读,不是裁决带来的新信息。按最新一次同名 run 取数(⛔ 不是原始 run 列表,⛔ 不是 required 子集),head
78e53b1883268d:读数 值 distinct check names 34 success / skipped 28 / 3 failure 2 —— Test Core、Test Core (1/6)in_progress 1 —— Lint & Repo Gates成因也自行核到,⛔ 不只采信裁决。树上仍写退役键的测试文件恰是裁决点名的两个:
git grep -lP '\bsyncConfig\b' <head> -- '*.test.ts' → 5 个文件 每个文件里 syncConfig 与 schedule 同现的行数: cron-typed-positions-retirement.test.ts 15 ← 本 PR 新增的 pin,预期 connector-author-shape.test.ts 5 ← ⛔ 漏网 typed-expression-envelope-dialect.test.ts 5 ← ⛔ 漏网 connector.test.ts 0 automation/sync-retirement.test.ts 0 lit control: 提到 connectors 的测试文件 32 个⭐ 两个漏网文件都不在报告里那份「13 文件
--project local」跑批中,而 fixture 分诊表自称「每个写过这些键的测试都重判过」。⇒ 下一轮跑pnpm --filter @objectstack/spec test整包,⛔ 不再挑文件;挑文件正是这次漏掉它们的机制。B2 —— 席位裁定:(b),补 D3 条目,并删掉那条反向 pin
裁决 #15954(评论
5559778263)的字面:one ADR-0087 D3 semantic entry per family (export API, automation state, connector sync, cache warmup, DR/backup) …
connectors[].syncConfig.scheduleis the one stack-collection member: its D3 entry says so and names the measured zero in-repo authors and the NOT-MEASURED out-of-repo population.实现取的是 D2-only,并把「无 D3 孪生」写成断言
expect(step!.semantic.filter(/sync-schedule|connector-sync/)).toEqual([])—— 把对裁决的偏离固化成了合同。⛔ 本席不能批准 (a)。批准一个偏离维护者裁决字面的形状,就是代维护者答;这条红线不因为理由好而松动,而实现者的理由确实好。协议对这一刻的规定是明确的:裁决明令的动作在实施中测出对向事实 ⇒ 照字面执行,被打断行为的 pin 反转为拒绝 pin。 这里的对向事实是真的 —— 复核实测
connector-error-mapping-removed是 D2-only 且确无 D3 孪生(grep -c error-mapping= 2,两处均为conversionIds行与注释),院规registry.ts:9也写着「semantic list is the non-lossless residue D2 could not express」。⇒ 因此:照字面补 D3,那条反向 pin 删除(它是被打断行为的 pin,按同一条款反转);同时本席把「D2 已表达的退役是否仍欠一条 D3 孪生」作为约定冲突立进决策箱,让维护者一次性裁掉,而不是每张退役卡各自重打一遍。⛔ 本 PR 不等那张卡:它是受管面、draft-only、本来就不挂 auto-merge,异议窗口天然存在。
⭐ 并且 (a) 里那件真正重要的事在 (b) 里也必须做,它不是 (a) 独有的:人口测量与 NOT-MEASURED 声明目前只活在三处不投影的注释里,而 D2 唯一会投影的字段是
summary。裁决要求这句话被人读到。所以无论条目形状如何,那句话必须落在会投影的字段上。复核把这一点讲得比裁决本身更清楚,记在这里以免下一轮又只改形状不改可见性。本席自行核对、与裁决一致的部分
按家族拆分成立:七个位置里只有
DataSyncConfig.schedule从 stack manifest 可达(stack.zod.ts:685→connector.zod.ts:955→:799),另有一份独立佐证 ——typed-expression-envelope-dialect.test.ts自述 stack 可达的 typed 槽位是三个,connectors[].syncConfig.schedule是其中之一。受管面预算 454 → 454(本席 13:0xZ 已独立量过),维护者速读(草稿)在,席位意见待本席填。下文自
FAIL起为裁决原文。
FAIL
Implemented-by: claude/issue-16320-retire-cron-typed-positions Reviewed-by: contract-review-tier subagent, domain:spec seat总判
两条绑定项。① PR head 在 CI 上已红(Test Core 1/6
failure,job 102476306215):两个实施者既未触碰、也未纳入其"13 文件--project local"跑批的 spec 测试文件仍在写connectors[].syncConfig.schedule——恰恰是七个位置里唯一能从 stack manifest 写到的那个;实施者 fixture 分诊表自称"每个写过这些键的测试都重判过",漏了两个。② 对 #15954 裁决原文的偏离未经席位批准即被 pin 固化:裁决明文要求 connector 家族有 D3 条目并在其中写明人口测量;实施者只做 D2、pin 断言"无 D3 孪生",而人口/NOT-MEASURED 陈述只落在代码注释里,投影面(D2 唯一投影字段summary)不含它。按家族拆分本身(只有 connector 可达)经我独立复算成立;D7 台账行删除、requiredness 边界、受管面预算、semver、ADR-0087 门禁均核对无误。① 派生判断(accept-set / 发布面变化,逐项)
# 变化 判定 读数 1 ScheduledExport.schedule.cronExpression:required →retiredKey()(z.never().optional())对。不可达: git grep -P '\bScheduledExportSchema\b' origin/main -- packages/** examples/** apps/** ':!<declaring>' ':!*.test.ts'→ 仅 D7 台账 + api-surface/declaration-map/export-origins 目录(非消费者);对照ConnectorSchema同查 = 123 行。类型名ScheduledExport在 spec 外 = 0(对照Connector= 74)D3 export-schedule-cron-retired,无 D2,无 migrate 句 ✓;reference 页export.mdx行由✅变never / optional / [REMOVED]✓2 ScheduleExportRequest.schedule.cronExpression:同上对,同 1 同一 D3; contracts/export-service.ts手写ScheduleExportInput.schedule.cronExpression同步删除(见 E)3 ScheduleState.cronExpression:REQUIRED → tombstone;requiredness 随键离开对。 ScheduleStateSchema/ScheduleState在 spec 外 = 0(对照上),spec 内声明文件外 = 0(对照FlowRunSummary= 3 文件);调度触发器读的是 start nodeconfig.schedule(packages/triggers/trigger-schedule/src/index.ts:4 normalizeSchedule)。带键的旧行 →invalid_typeat['cronExpression']附处方;不带键 → 解析通过,timezone='UTC'、status='active'(pincron-typed-positions-retirement.test.ts"requiredness left with the key" +execution.test.ts:777-795把原toThrow改为not.toThrow)无存储消费者,故不存在"已存行全部拒绝"风险 4 DataSyncConfig.schedule:optional → tombstone;唯一可达位对。 stack.zod.ts:685 connectors: z.array(DeclarativeConnectorEntrySchema)→connector.zod.ts:955→:799 syncConfig;/meta/connector门metadata-type-schemas.ts:254。独立佐证:typed-expression-envelope-dialect.test.ts:155-157自述"stack 可达的三个 typed 槽位 =jobs[].schedule.expression、connectors[].syncConfig.schedule、objects[].titleFormat"D2 connector-sync-schedule-removed(toMajor 18,retiredFromLoadPath,mapCollection('connectors')),registry.ts:5438已接入 step18conversionIds;stored seam:manifest-collection-spelling.ts:94 connectors:'connector'(对照:60 objects:'object');migrate 句措辞与 errorMapping 先例一致(connector.zod.ts:496"removed in @objectstack/spec 17"、:505 --from 17,toMajor:18)✓5 CacheWarmup.schedule:optional → tombstone对。 CacheWarmupSchema/DistributedCacheConfigSchema声明文件外 = 0(仅目录);stack.zod.ts无 cache 集合键D3 cache-warmup-schedule-retired;strategy:'scheduled'枚举成员保留且失活(见 ③)6 BackupConfig.schedule:optional → tombstone对。 BackupConfigSchema声明文件外 = 0D3 disaster-recovery-schedules-retired;carrierDisasterRecoveryPlan.backup有 pin7 DisasterRecoveryPlan.testing.schedule:optional → tombstone对。 DisasterRecoveryPlanSchema声明文件外 = 0同一 D3;嵌套拼写 system/DisasterRecoveryPlan:testing.schedule,先例18.api__BatchEndpointsConfig__operations.upsertMany.ts:25存在 ✓8 无 .default()残留对:七位均无 .default(),acceptRetiredDefaultResidue类不适用;已构建工件无发射默认值— 9 发布 skill objectstack-formulacron 行 Carriers 单元格 −3 名对。`git show origin/main:skills/objectstack-formula/SKILL.md wc -l = **454**;78e53b1= **454**;merge-basece7bae8= 454。git diff仅 1 行:Job.schedule.expression (canonical)保留,template` 行未动10 authorable-surface:恰 4 行翻为 [RETIRED](automation/ScheduleState:cronExpression、integration/DataSyncConfig:schedule、system/BackupConfig:schedule、system/CacheWarmup:schedule)对,三嵌套位无自有行 RETIRED_KEYS_BY_MAJOR[18]生成区在 head 含全部 7 拼写(registry.ts:10920,10953,11058,11291,12209,12247,12336)11 spec-changes.json/ upgrade guide 字节不变对且正确: build-spec-changes.ts:96只折叠到PROTOCOL_MAJOR;对照 step-18 既有条目metadata-plugin-additional-types-retired/connector-error-mapping-removed在 origin/main 两文件计数 = 0/0,etl-pipeline-layer-retired(step 17)= 2/1但这也意味着 D2 summary是 connector 家族未来唯一会投影的文字(spec-changes.ts:103-105 {surface, to: summary})——见绑定项 2按家族拆分与 pin 的判定:
- 裁决原文([Decision] nine cron- and template-typed keys in packages/spec are published, documented and read by nothing — retire them under ADR-0049 (the #14477 / #15513 shape), mark them experimental, or leave them? #15954 评论 5559778263):"one ADR-0087 D3 semantic entry per family (export API, automation state, connector sync, cache warmup, DR/backup) …
connectors[].syncConfig.scheduleis the one stack-collection member: its D3 entry says so and names the measured zero in-repo authors and the NOT-MEASURED out-of-repo population." 卡片正文同义。四个不可达家族各一 D3、无 D2、无 migrate 句 → 满足裁决(且是唯一可能的形状:无 seam 的 conversion 从不运行)。connector 家族 D2-only → 偏离裁决原文。 - errorMapping 先例:
conversions/registry.ts:8445 connector-error-mapping-removed(toMajor 18,retiredFromLoadPath,mapCollection('connectors'));git show origin/main:…/migrations/registry.ts | grep -c error-mapping= 2,均为conversionIds行与注释——确无 D3 孪生,实施者所述形状属实;院规registry.ts:9"semantic list is the non-lossless residue D2 could not express" 与之相容。 - pin 逐项:20 个用例(7 sites + 1 envelope + 4 carriers +
/meta/connector+stack.connectors[]+ 2 no-materialize + 1 tsc + 3 ADR-0087)。按源码推演消融:M1(CacheWarmup 复活)→ SITES[4] + CARRIERS[3] + tsc 运行时 sweep = 3/20 ✓;M2(去 D2)→ 仅 "connector family converts" 用例 = 1/20 ✓;M3a(去 migrate 句)→ SITES[3] + CARRIERS[0,1] +stack.connectors[]= 4/20 ✓(/meta/connector门用例不查 message,故不红);M3b → SITES[4] + CARRIERS[3] = 2/20 ✓。四组数字均可从源码复现。任一家族 D3 被删 →expect(entry).toBeDefined()红,无该类漏洞。漏洞(非绑定):envelope 拼写仅覆盖 2/7(但z.never对任何值一律拒绝,冗余);/meta/connector门用例不断言 path/message;无applyConversionsToStoredItem('connector', row)存储回放用例(stored.test.ts中connector= 0 命中)。 - pin 第 20 个用例
expect(step!.semantic.filter(/sync-schedule|connector-sync/)).toEqual([])把裁决偏离写成了合同——见绑定项 2。
② semver 定级
- Changeset
@objectstack/spec: minor+ 字面**BREAKING** — an accept-set narrowing on seven authorable positions+<!-- adr-0087: registered <5 ids> -->。 - 门禁实际判定(自建
/tmpworktree @78e53b188,已清理):node scripts/check-adr-0087-registration.mjs --base origin/main --head 78e53b188→ exit 0,输出[BREAKING+bang] registered connector-sync-schedule-removed, export-schedule-cron-retired, schedule-state-cron-expression-retired, cache-warmup-schedule-retired, disaster-recovery-schedules-retired (new here: 全部五个)——信号来自breakingDeclaration()/\*\*BREAKING/i+feat(spec)!:,不是空跑。node scripts/check-changeset-no-major.mjs --base origin/main --head 78e53b188→ exit 0 无major;level 轴本地 N/A(需 PR payload),CICheck Changeset×2 success。 - 定级正确:仓库惯例为启动窗口内 breaking 走
minor(check-changeset-no-major.mjs头注;packages/spec/CHANGELOG.md≥20 处 "shipped asminorunder the repo's launch-window convention")。required→retired 不改变级别。Clause-②: yes双载体一致(PR 正文、claim 5601364015),卡与 PR 均带needs:contract-review。
③ 边界旗处置
CacheWarmup.strategy保留'scheduled'(describe 仍写 "scheduled (cron)")、四条 ratchet 均看不见 —— 同意事实,不同意 承接者:无:PM 派发前读数已标注"invisible to all four ratchets",应立一张小卡(枚举值 ADR-0049)而非无人承接。非绑定。ScheduledExport.schedule/ScheduleExportRequest.schedule变为只含可选timezone的必填对象;ScheduleState.timezone/status/nextRunAt孤儿;ExportJobApiContracts全家零消费者 —— 同意,升级为一张needs-user-decision候选(家族级退役),非本卡。docs/adr/0122:73陈述已过时 —— 同意不改(ADR 为记录)。etl-pipeline-layer-retiredreplacement 文案 "IS parsed and executed"(spec-changes.json:739, guide:443)—— 同意,docs-only 小卡。- 平台追加的第二页脚 —— 无动作。
应标而未标:
- ⭐ 两个仍写
syncConfig.schedule的 spec 测试(绑定项 1)——其 fixture 分诊表与"tsc 全树守卫"论断均未覆盖它们(它们分别用 TS 编译探针与ObjectStackDefinitionSchema走 stack 路径)。 - ⭐ 对裁决原文的偏离列在
deviations而open_questions: []——偏离维护者裁决字面应作 open question 交席位裁定,不能自批。 shared/expression.zod.ts:263-270文档块仍写 "Use this forschedule/cronExpressionfields … every other cron-typed slot reaches no engine":此 PR 后除 Job 只剩KnowledgeRefreshPolicy.cron,措辞漂移。非绑定。- 普查"4 处 bare-word
cronExpression"漏计docs/qa/platform-checklist/areas/dashboards.json:1068,1079(同为 plugin-reports 键,POST /api/v1/reports)。不改结论。 - CI 读取时
Test Core 3/6、5/6、Lint & Repo Gates、Type Check · workspace仍in_progress,未结论。
其余问题的读数
- A requiredness:见 ① 第 3 行。
- D D7 台账:discovery 正则
^\s*\w+\s*:\s*CronExpressionInputSchema\b在78e53b188 -- packages/spec/src/**/*.zod.ts→ 2 处(ai/knowledge-source.zod.ts:48,system/job.zod.ts:16);对照 origin/main = 9;五文件中CronExpressionInputSchema引用 = 0。七个 cover 全部离开 discovery ⇒ 任一保留都读 STALE,整行删除是必需而非选择;failPolicy:'unevaluated'行在 head 仍剩 4 条(cron-knowledge-refresh,template-prompt,template-title-format,cel-advanced-policy),套件的 unevaluated pin 不空转。CIDogfood Regression Gate×3 success。 - E export-service.ts:
IExportService.scheduleExport()返回ScheduledExport(其schedule.cronExpression现为never),输入接口再要求cronExpression: string即自相矛盾,删除合理;头注:15自记 "no evidenced provider binding"。残留contracts/report-service.ts:105 cronExpression?: string是 plugin-reports 的不同键(report-service.ts:636,rest-server.ts:12541,client/src/index.ts:5778,5786),不在七位之列 ✓。 - F 普查:
\bcronExpression\bspec 外(排 tests/changelogs/releases)→ 代码位仅 reports 4 处 + 生成 reference 页 + D7 台账 + SKILL.md(本 PR 均已改),对照含 spec/src = 7 行;\bsyncConfig\bspec 外 → 仅 ADR-0097/0122 散文、upgrade guide:443,445、生成 connector.mdx、台账,对照 spec/src = 8 文件;七 def 名 spec 外 →docs/adr/0122:254、guide:444、台账,对照 = 13 文件;examples/apps/skills 无syncConfig/warmup/backup作者块(对照 examples 中connectors= 14 文件);json/yaml/qa 无syncConfig.schedule(对照connectors= 17 文件)。objectui @53ded82bf7a4(.objectui-sha:1;/home/user/objectui在3fbdd4a,只读git grep <sha>):七名 +cronExpression→ 仅ROADMAP.md:63散文;syncConfig→ 全在packages/react/src/hooks/useOffline.ts自有键;对照ConnectorSchema|defineStack= 29 文件。零作者成立;仓外 NOT MEASURED 如实标注 ✓。 - tombstone 文案中
cronEngine has zero consumers outside its own package:git grep -l '\bcronEngine\b' origin/main -- packages/** ':!packages/formula/**'→ 仅 D7 台账;对照 formula 内 = 5 文件 ✓。 connector.mdxhead 含[REMOVED] \connector.syncConfig.schedule`` = 3 行(origin/main = 0)✓。
绑定项(一轮可完成)
B1 · CI 红:两个既有 spec 测试仍写
connectors[].syncConfig.schedule,须重判并修正。 读数:get_job_logs 102476306215→@objectstack/spec:test5 个断言失败:packages/spec/src/integration/connector-author-shape.test.ts:455,461,465(SYNC_ARCHITECTURE.md的 L3Connector示例不可编译,且写的是 schema 会**拒收**的键名(sourceField/targetField/transform.type: 'custom'/ webhookretryPolicy) #5515/ADR-0122 注释形状 pin:literalsyncConfig: { schedule: '*/15 * * * *' }用 TS 编译探针期望Connector下''、ConnectorParsed下含dialect,并ConnectorSchema.parse期望信封)——现分别得到TS2322 … 'undefined'、缺dialect、ZodError invalid_type at syncConfig.schedule。packages/spec/src/shared/typed-expression-envelope-dialect.test.ts:177,197([finding]CronExpressionInputSchema/TemplateExpressionInputSchemafix the dialect only on the bare-string arm — the envelope arm accepts any declared dialect, so a cron-typed slot parses{ dialect: 'cel', source }green #15028/[finding] The shared cron dialect judges no cron syntax at parse time — after #14825 all 9CronExpressionInputSchemasites accept'not a cron'green; the verdict is the formula cron-engine's at evaluate time #15035 收窄 pin:stack 可达 typed 槽位控制组与connectors.0.syncConfig.schedule的invalid_union断言)——现得到 tombstone 的invalid_type。
全树git grep -P '\bsyncConfig\b' 78e53b188 -- '**/*.test.ts'证明漏网集合恰为这两个文件(sync-retirement.test.ts:211-225与connector.test.ts:472的syncConfig不含schedule)。修法:前者的"cron 信封"半边改用另一个 input/parsed 有别的键(该测试自述 "every.default()key becomes required",defaults 半边仍成立);后者把 connector 从"三个 stack 可达 typed 槽位"名册中移除并改为断言 tombstone 在connectors.0.syncConfig.schedule的invalid_type(或删除该 case 并改文档块)。PR 正文 fixture 分诊表须补这两行;pnpm --filter @objectstack/spec test完整跑一次(不是挑 13 文件)后再报。
B2 · 裁决原文的 connector 条款未落在任何投影面,且偏离未经席位裁定即被 pin 固化。 裁决要求 connector 家族 D3 条目"says so and names the measured zero in-repo authors and the NOT-MEASURED out-of-repo population";head 上该陈述只在
18.integration__DataSyncConfig__schedule.ts注释、conversions/registry.tsdocblock、connector.zod.ts段注释——三者均不投影;D2 唯一投影字段summary(spec-changes.ts:105)不含它。两条路,席位择一并在卡上留字:(a) 批准 D2-only 形状(errorMapping 先例 +registry.ts:9院规支持),并把人口/NOT-MEASURED 一句写进connectorSyncScheduleRemoved.summary(可被os migrate meta/spec-changes/upgrade guide 投影),PR 正文把该偏离从deviations移到已裁定项;或 (b) 按裁决字面补18.connector-sync-schedule-retiredD3 条目(residue = 仓外人口的人工核验 TODO,配 acceptanceCriteria),并删除 pin 中semantic.filter(/sync-schedule|connector-sync/)).toEqual([])的反向断言。非绑定项
shared/expression.zod.ts:263-270文档块措辞更新(见 ③)。- pin 覆盖补强(可选):
/meta/connector门用例断言 path/message;补一条applyConversionsToStoredItem('connector', {syncConfig:{schedule}})回放用例,让retiredFromLoadPath的存储 seam 有本家族证据。 - ③ 第 1、2、4 项各立卡。
- 普查计数补
dashboards.json两处(结论不变)。
Generated by Claude Code
- 裁决原文([Decision] nine cron- and template-typed keys in packages/spec are published, documented and read by nothing — retire them under ADR-0049 (the #14477 / #15513 shape), mark them experimental, or leave them? #15954 评论 5559778263):"one ADR-0087 D3 semantic entry per family (export API, automation state, connector sync, cache warmup, DR/backup) …
os-dev-report
{ "issue": 16320, "status": "done", "branch": "claude/issue-16320-retire-cron-typed-positions", "pr": "https://github.com/objectstack-ai/objectstack/pull/17146", "premise_still_valid": true, "summary": "Resumed a patch round that lost two agents mid-round (account usage wall ~14:15Z; model-scoped limit ~17:5xZ). NEITHER death cost any work: I measured the tree before trusting either one's last words. Both predecessors' commits were already pushed and complete — wip 60e293676 (connector-family D3 twin per the #15954 letter, both missed fixtures re-judged, pins hardened) and wip 172c32638 (name the tool without the house-sentence marker in the D3 twin, for the repo-tier class pin retired-key-migrate-sentence). The second agent died in its READING phase, having already landed its edits, so its last message understated what was done. What I added this round: merged origin/main 4261fbc80 through scripts/pm/os-regen-merge.sh (merge commit e5e87ccba, pushed); ran the verification the seat's FAIL demanded and the round had never run; corrected the bare-word census; rewrote the PR body (Verification, a new 'Contract review round 2' section, two Fixture-triage rows, the three filed cards). BINDING B1 (CI was RED — two spec tests still authored connectors[].syncConfig.schedule, neither in the first round's hand-picked 13-file run) is CLOSED: connector-author-shape.test.ts had the retired key dropped from its ADR-0122 flip probe so the flip is measured on the defaults alone plus a positive not.toHaveProperty('schedule'); typed-expression-envelope-dialect.test.ts had the stack-reachable typed-slot roster shrunk from three to two HERE, its connector case kept as the tombstone it now is (all three former inputs draw invalid_type at connectors.0.syncConfig.schedule, explicitly NOT the dialect verdict, with a control asserting the same connector minus the key still parses). BINDING B2 (route (b), the seat's choice) is CLOSED: D3 entry 18.connector-sync-schedule-retired exists with acceptanceCriteria; the reverse assertion that had encoded the deviation as contract is deleted, inverted to assert the twin; and the part the ruling actually cares about — the population sentence — now sits on fields that PROJECT (the D3's reason, which projects to spec-changes.json rationale, the upgrade guide's 'Why not automatic' and os migrate meta's why:, and acceptanceCriteria, which projects to 'Done when' and verify:), with the D2's one projecting field, summary, naming the twin as the carrier of the residue. It previously lived only in three non-projecting code comments. I did NOT re-open the D2-only argument; decision card #17152 owns it and this PR does not wait on it. PR remains DRAFT with needs:contract-review intact — governed surface, a human merges. I performed no contract review and flipped nothing.", "tests": "ALL heavy runs under scripts/pm/os-verify-lock.sh with a stable OS_VERIFY_LOCK_SLOT; first attempt returned exit 99 queue-timeout (recorded NOT MEASURED, never a pass) and the slot resumed its place rather than re-queuing. FULL SPEC SUITE, the binding B1 item — 'pnpm --filter @objectstack/spec test' (= vitest run --project local): 471 test files, 13222 tests, ALL PASSED, exit 0, lock VERDICT 'command-exit 0' held 763s. NO file hand-picked. Reconciled against the config so 471 is not a bare number: 'vitest list --filesOnly' collects 499 = 471 [local] + 28 [repo], and the package test script is --project local, so 471 IS the whole local project; both files the review named are in it ([local] src/integration/connector-author-shape.test.ts, [local] src/shared/typed-expression-envelope-dialect.test.ts), with integration/connector.test.ts lighting the control. REPO TIER, which pnpm test does NOT run and which owns the class pin retired-key-migrate-sentence.test.ts the second predecessor's commit targeted — vitest run --project repo: 28 files, 410 tests passed, exit 0, lock VERDICT command-exit 0. Builds: dependency closure and spec build both exit 0. check:generated exit 0 — 'All 15 generated artifacts are up to date', nothing stale so NOTHING regenerated and there is no regeneration commit. typecheck exit 0. GATES: derived, never hand-fed — 'node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack' (script derived its own change set, 42 paths vs merge base 4261fbc80; the --repo assertion checked against this checkout's origin and holds) = 110 families; every one run with its exit code redirected to its own log and captured BEFORE reading (eval cmd >> log 2>&1; ex=$?, never across a pipe); reconciled with --ran: '110 derived famil(ies) accounted for — 110 run, 0 NOT-MEASURED', exit 0. 109 green on the first pass. The single non-zero was 'pnpm check:type-check-debt' exit 3 = PREREQUISITE NOT MET, which I recorded as NOT MEASURED and NOT as a red: its self-test and coverage legs passed (76/80 packages) and only the --re-measure leg OOM'd, because tsc inherits the caller's NODE_OPTIONS ceiling, which the gate's own output flags as tighter than its process limit. Re-ran with that ceiling raised 4096 to 8192 (the gate's prescribed repair — it refuses to record 0 rather than emit a false green): exit 0, '5 ledger entr(ies) re-measured, 55 raw tsc errors, none above its recorded number', lock VERDICT command-exit 0. CI's own 'Type Check · debt ledger' is green on this head, agreeing. LINT narrowed AND proven a measurement, all three readings present: population read from eslint.config.mjs itself (eslint . minus NEVER_LINTED); count read from --format json (31 lintable files of the 42-path diff, 0 errors, 0 warnings, exit 0, --no-inline-config); invariance — no parserOptions.project and no typed @typescript-eslint rules (config comment at :328), so type-aware linting is off and this diff cannot move a rule's verdict on an untouched file, hence the narrowing excludes nothing. GOVERNED BUDGET: skills/objectstack-formula/SKILL.md 454 -> 454 lines, NET 0 (git show origin/main:PATH and git show HEAD:PATH both 454) — within 'net <= 0, never more than +2'. No ablation was owed or run this round: the four reverse-verification legs are the earlier round's and remain documented in the PR body; I added no new gate needing a fresh failure proof, and the tree is clean (git status --porcelain empty). Shallow-checkout discipline: every ancestry reading carried a control leg that answered exit 0.", "mcp_calls": "0 — the whole run went through repo-scoped REST (a probe returned HTTP 200 first). The /search/issues endpoint is NOT available to this session ('sessions are bound to their configured repositories'), proven with a lit control that also came back empty, so duplicate-checking used the sanctioned fallback: the REST list endpoint plus local grep over 379 open issues, with 'cron' lighting the control at 10 hits.", "open_questions": [], "out_of_scope_findings": [ "filed as #17157: CacheWarmup.strategy keeps the 'scheduled' enum member after its cron left — a declared-but-inert value, invisible to all four ratchets (boundary flag 1; the seat rejected 'noted, not filed' for it).", "filed as #17158: the export-job API contract family (ScheduledExport / ScheduleExportRequest / ExportJobApiContracts) has zero consumers family-wide — opened as a needs-user-decision candidate (boundary flag 2). I did NOT decide it, per the dispatch.", "filed as #17159: the etl-pipeline-layer-retired D3 entry's replacement text says connector-attached sync 'IS parsed and executed', a stale claim in a registered, projected ledger string (boundary flag 4).", "noted, not filed: docs/adr/0122:73 records the parsed syncConfig.schedule shape as it was when written. An ADR is a governed record and is not rewritten for a later retirement — 承接者:无, deliberately, because the correct handling is to leave it.", "noted, not filed: the census correction the review asked for is applied in the PR body — the bare-word cronExpression count goes 4 to 6, adding docs/qa/platform-checklist/areas/dashboards.json:1068,1079. Both are the plugin-reports key (POST /api/v1/reports/:id/schedule), a DIFFERENT key from the seven, so the conclusion is unchanged.承接者: this PR body itself.", "noted, not filed: GitHub appends its own bare 'Generated by Claude Code' footer to the PR body on top of the session-URL footer I write (the review's boundary flag 5). Read back and confirmed as a pure suffix — the body I sent survived byte-for-byte. No action." ] }
Generated by Claude Code
7 remaining items
os-dev-report
{ "issue": 16320, "status": "done", "branch": "claude/issue-16320-retire-cron-typed-positions", "pr": "https://github.com/objectstack-ai/objectstack/pull/17146", "premise_still_valid": true, "head_sha": "2095e4e918299c68601788247e1302fd63e55ef9", "summary": "Applied the CONTRACT_REVIEW_TIER must-fix to PR #17146. ONE new commit (2095e4e918), wording only — no behaviour code changed, the seven deletions / the merge / the ADR-0087 disposition were not reopened. M1: all four sites that called the strip 'silent' are corrected, after I re-measured the reviewer's claim myself at the PR head and it held in every leg. Clause-2 is restated as SEVEN widenings (three of them required-key removals), each verified on a real base leg rather than transcribed. A2 is named in the changeset with its sweep. A3 gets one line in the PR body and nothing else. Root cause posted to #17356. One thing beyond the dispatch: `check-clause2-carriers --pair 17146` exited 4 on a SPLIT dual carrier — `needs:contract-review` was on the PR but NOT on card #16320. I hung the card half additively (POST .../labels, read back, nothing stripped); the PR's label was not touched. Pair now exits 0.", "m1_four_sites": { "verification_before_editing": { "os_validate": "exit 0, prints `connectors.sap_erp.syncConfig.schedule: 'schedule' is not a declared connector key, so its value is dropped at load.` — lit 4 warnings vs dark control 3, the delta is exactly that line; --json carries the identical string in `warnings`", "os_validate_strict_isolated": "on an OTHERWISE-CLEAN stack: dark control (no key) = 0 warnings, exit 0; lit (with key) = 1 warning, exit 1. A CI running --strict refuses the upgraded manifest.", "os_build": "exit 0, prints the same line under `Undeclared authoring keys (1) — dropped at load (#3786)`; dark control prints no such block", "os_migrate_meta": "exit 0 with `--from 17` and `--from 16`; 0 occurrences of `cronExpression` and no prescription for any of the seven in either output", "mechanism_read_in_source": "`lintUnknownAuthoringKeys` (metadata-authoring-lint.ts:411) loops PLURAL_TO_SINGULAR; `connectors: 'connector'` is at meta-spelling/manifest-collection-spelling.ts:94; validate.ts strict slot `flags.strict && warnings.length > 0 ? 1 : 0`; compile.ts prints the same list" }, "site_1_pr_body_maintainer_brief": "REWRITTEN. Was 「静默丢弃,没有报错、没有警告、没有任何可 grep 的痕迹」. Now states the cost per channel in Chinese, decision-grade: parse 层静默剥除 / `os validate` 点名该键(exit 0)/ `os validate --strict` exit 1 拒收(带隔离对照读数)/ `os build` 同样点名 / `os migrate meta` 什么都不列;plus the mechanism, plus an explicit note that the correction is MORE favourable to authors than the previous text, plus the 'you must do' line rewritten to name the four channels. 前提核验 section's 证伪 paragraph corrected in the same pass.", "site_2_changeset": "REWRITTEN. Was 'the value is discarded without a word. Nothing refuses it'. Now: the parse drops it silently, then a bullet list — `os validate` / `os build` NAME the key (string quoted), `--strict` EXITS 1, `os migrate meta` still lists nothing, `tsc` names it — and a closing sentence that the other six positions are unreachable from a manifest so for those the parse-level strip really is all of it. The sibling 'nothing refuses it' sentence in the 'no before/after rewrite' section was corrected too (it is a statement about the migration chain, not about silence).", "site_3_registry_ts_step18": "REWRITTEN. Was 'stripped in silence rather than refused'. Now: the chain being silent does NOT make the deletion silent to an author — parse strips, `lintUnknownAuthoringKeys` names the key for the one reachable position, `os validate --strict` EXITS 1, the other six are unreachable. `check:generated` exit 0 afterwards confirms this rationale is hand-maintained text, not a generated region.", "site_4_pin_test": "REWRITTEN at BOTH places, not only :280. (a) the module docblock's 'That makes the observable consequence a SILENT STRIP' now says PARSE-LAYER consequence and carries the four measured CLI readings plus a ⛔ line saying these pins pin the schema layer and must not be quoted as what the author is told; (b) the :280 comment's 'discarded without a word — the ADR-0104 silent-strip shape' now says silent at the PARSE, names the three CLI channels, and states that this assertion is about ObjectStackSchema alone." }, "seven_widenings_independent_verification": { "method": "NOT transcribed. Two real legs. The five schema files were restored on disk from the merge-base (cca1dc0bfb1e) with `git checkout $BASEREF -- FILE`, one probe run (base leg), then `git checkout HEAD -- FILE` and the probe re-run (head leg). Mutation proved on disk before measuring: CronExpressionInputSchema occurrence counts went 0/0/0/0/0 -> 3/2/2/2/3 across the five files and `git diff HEAD` was non-empty; restore proved after: `git diff HEAD` empty and all 5 on-disk `git hash-object` values equal to their `HEAD:PATH` blob (no empty hash). Script carried `trap restore EXIT INT TERM` with absolute paths from `git rev-parse --show-toplevel`.", "result": "14 cases. BASE leg: 14/14 success=false, every one `invalid_union` at the expected path. HEAD leg: 14/14 success=true with the key absent from parsed data. 5 positive controls (well-formed fixtures) success=true in BOTH legs.", "rows": [ "automation/ScheduleState:cronExpression — REQUIRED. doc lacking the key: base invalid_union@cronExpression -> head accepted. value 42: base refused -> head accepted+stripped. CONFIRMED.", "api/ScheduledExport:schedule.cronExpression — REQUIRED (source: `cronExpression: CronExpressionInputSchema` with no .optional()). `schedule: {}`: base invalid_union@schedule.cronExpression -> head accepted. CONFIRMED, and it was NOT named in the previous PR body or changeset — now named.", "api/ScheduleExportRequest:schedule.cronExpression — REQUIRED. same two inputs, same answers. CONFIRMED.", "integration/DataSyncConfig:schedule — optional union. wrong-dialect envelope {dialect:'template'} AND value 42: base invalid_union@schedule -> head accepted+stripped both. CONFIRMED.", "system/CacheWarmup:schedule — optional union, same class, both inputs. CONFIRMED (the reviewer's `{dialect:'template'}` probe reproduces).", "system/BackupConfig:schedule — optional union, same class, both inputs. CONFIRMED.", "system/DisasterRecoveryPlan:testing.schedule — optional union. wrong-dialect envelope and value 12: base invalid_union@testing.schedule -> head accepted+stripped. CONFIRMED (the reviewer's `12` probe reproduces)." ], "verdict": "Clause-②: yes stands. SEVEN, not two; THREE required-key removals, not one. The PR body now says seven and carries the full base/head table. The anchored `Clause-②: yes` line still STARTS a line in the stored body (verified on read-back).", "deviation_from_the_review": "none on these seven rows — every row reproduced." }, "a2_sweep": { "action": "The changeset now carries a dedicated paragraph naming the departure of the required `cronExpression: string` member from `ScheduleExportInput` (input type of `IExportService.scheduleExport`), and says explicitly that 'no def leaves the public surface' is true but does not cover a member. Both names confirmed published: they are in `packages/spec/api-surface/contracts.json`.", "sweep": "objectstack: `git grep -n 'ScheduleExportInput'` and `'IExportService'` outside packages/spec = 0 hits (grep exit 1). Positive control in the same sweep: a comparable published symbol resolves in 5+ files outside packages/spec, so the zero is a reading and not a broken grep. objectui: 0 hits for either name; control = 1326 files there import @objectstack/spec.", "cloud": "NOT MEASURED — the `cloud` repo is not checked out in this container (only /home/user/objectstack and /home/user/objectui exist). Declared as NOT MEASURED in the PR body too." }, "a3": "Noted, not acted on. One line added to the PR body under a new heading saying the regenerated content/docs/references/integration/connector.mdx carries generator drift unrelated to this PR (`strategy?:` -> `strategy:` on defaulted keys), that main's copy was stale relative to its own generator, that check:docs is green at head, and that it must not be read as a schema change. No file touched.", "issue_17356": { "posted": true, "comment": "https://github.com/objectstack-ai/objectstack/issues/17356#issuecomment-5616358457", "labels_or_state_changed": false, "verified_before_posting": "yes, and the reviewer's claim reproduces with ONE correction. Measured with OS_EAGER_SCHEMAS=1: listMetadataTypeSchemaTypes() = 26 types, includes connector=false, webhook=false, sharing_rule=false; ALL-ROOTS BFS closure = 5420 nodes and does NOT contain DataSyncConfigSchema, while the positive control ObjectSchema IS in that same closure; CONNECTOR-ROOT closure = 438 and DOES contain it; syncConfig unwraps through exactly one `optional` to the exported instance. The gate docblock's claim 'i.e. the schemas a metadata document is actually parsed against' is quoted verbatim from build-schemas.ts. => root enumeration, not an edge bug and not a def-key-map bug.", "correction_to_the_review": "the review said UNREGISTERED_KIND_SCHEMAS holds THREE entries (connector/webhook/sharing_rule, per #6245). It holds FOUR today: analytics_cube, connector, sharing_rule, webhook (#10194 added theme and analytics_cube; #10485 later retired theme). The blast radius is therefore four unenumerated roots, not three. Reported in the comment.", "harness_trap_reported": "a static ESM import of these CJS-loaded spec modules from an .mts probe under tsx yields a SECOND instance and makes the probe answer `root === DeclarativeConnectorEntrySchema` false and `CONNECTOR-ROOT reaches DataSyncConfigSchema` false — i.e. it fakes the bug's signature. My first probe hit exactly this and I did not report its numbers. Every reading above comes from an all-dynamic-import probe carrying an identity-guard line. Written into the #17356 comment so the next person does not measure a false negative." }, "tests": "ALL at the new head 2095e4e918 unless noted; exit codes captured with `cmd > log 2>&1; EXIT=$?`, never through a pipe. Heavy runs through `scripts/pm/os-verify-lock.sh -c` with OS_VERIFY_LOCK_SLOT=issue-16320-m1 (VERDICT command-exit 0 each time; waited 0s). GREEN: `pnpm --filter @objectstack/spec build` exit 0 (`check-dts-emitted: 34/34 declared declaration file(s) present.`); `check:generated` exit 0 (`✓ All 15 generated artifacts are up to date.` — which also proves the registry.ts step-18 rationale is hand-maintained, not a generated region); `check:spec-changes` exit 0 (`spec-changes.json is up to date.`); `vitest run src/cron-typed-positions-retirement.test.ts src/migrations` exit 0 (`Test Files 2 passed (2)` / `Tests 136 passed (136)`); `typecheck` exit 0; `check:test-typecheck` exit 0 (`54 files / 261 errors / 145 pinned signatures` — same numbers as the previous round, ratchet untouched); `check-adr-0087-registration --base origin/main` exit 0 POST-COMMIT (`✓ 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.` / not-required (no-migration-prescription)) and `--self-test` exit 0 (338 assertions); `check-changeset-no-major --base origin/main` exit 0; `check-empty-changeset --base origin/main` exit 0 (1 declaring changeset); `pnpm check:changeset-gate-self-tests` exit 0 (118+338+265 assertions); `pnpm check:nul-bytes` exit 0 (8172 text files, no raw control bytes) PLUS the rule's own `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the three edited files, 0 hits; `check-skills-token-ratchet` exit 0 (36 authored files within ceilings; skills/** untouched this round); `check-spec-docblock-symbol-anchors` exit 0; `pnpm check:doc-authoring` exit 0; `check:pm-governed-merges` and `check:pm-governed-prose` exit 0; `npx eslint . --no-inline-config --format json` exit 0 — 6485 files, 0 errors, 0 warnings, NOT narrowed, run at final commit 2095e4e918. CLAUSE-2 PAIR: `node scripts/pm/check-clause2-carriers.mjs --pair 17146` exit 4 BEFORE (split carrier: label on PR, absent on card) and exit 0 AFTER hanging the card half (`both carriers agree`). NOT MEASURED, called out: (1) the FULL `pnpm --filter @objectstack/spec test` (471 files) was not re-run this round — the diff is three files of prose and the two suites that could read them (the pin test and migrations.test.ts) both ran; the previous round's full run stands and CI re-runs it. (2) `check:react-declaration-parity` — EXTERNAL_INPUT_REQUIRED, needs objectui's sdui.manifest.json at the pinned sha; not producible here, by design an on-demand gate. (3) The `cloud` repo half of the A2 sweep — repo absent from this container. (4) `dispatch-gates.mjs --commands` printed 114 commands but SELF-REPORTED **STALE TREE** (tree >= 4 commits behind origin/main, 14 files it derives from changed across that range) => its 'only more, never fewer' guarantee does not hold here; the increment belongs to PM reading real CI. ABLATION: none owed — no new guard was added this round. The base/head legs above are a two-sided measurement, not an ablation, and both legs are documented with their on-disk mutation proof and byte-identical restore.", "ci": "At head 2095e4e918, newest run per check NAME: 31 distinct names — 10 success, 4 skipped, 17 in_progress, 0 failure/cancelled/timed_out. Combined commit status: `success` (contexts: Vercel=success). Still running at report time: Build Core, Build Docs, Lint & Repo Gates, Test Core (1..6/6), Dogfood Regression Gate (1..3/3), Dogfood Verify CLI, Temporal Conformance (live PG + MySQL) and others. Reported as in_progress per the contract; no waiting, no polling.", "governed": "GOVERNED — re-derived from the FINAL file list, not from the dispatch: `git diff --name-only origin/main...HEAD` still contains `skills/objectstack-formula/SKILL.md`. PR stays draft (read back: draft=true). Never flipped ready, never enqueued, never armed auto-merge, never approved. `needs:contract-review` still on the PR (read back in the label list) and NOT removed by me. `skills/**` was NOT touched by this round's commit, so the skills line/token readings are unchanged from the previous round and check-skills-token-ratchet is green.", "mcp_calls": "0 — every GitHub read and write this round went through repo-scoped REST (session gate probed open with GET /repos/.../issues/16320 -> 200). No MCP GitHub call was made.", "open_questions": [ { "question": "The PR body cannot carry exactly ONE session-URL attribution footer on this channel. Measured two-way this round: raw REST `PATCH /pulls/17146` appends its own bare footer block unconditionally — once with my footer written as the canonical rule+footer block, once with the rule line removed per pm-dispatch `platform-readings.md` (「PR 正文页脚不带前置横线」). Both stored TWO footers. Only a body sent with NO footer at all stores exactly one (the platform's bare one).", "options": [ "A — what I shipped: body carries NO footer; the session id is written into body PROSE, which is where AGENTS.md says durable attribution lives, and the single stored footer is the platform's bare one. Read back: FOOTER COUNT = 1.", "B — leave two footers (one session-URL, one bare) to satisfy the dispatch's literal 'session-URL footer' wording.", "C — route the edit through MCP `update_pull_request`, whose measured behaviour on this repo is to DELETE the body's footer block (with a recorded counter-example), i.e. a coin flip between 0 and 1." ], "recommendation": "A, because the dispatch's hard requirement was EXACTLY ONE and AGENTS.md's own remedy for this mutation class is prose attribution rather than re-posting footers. The session id is present and greppable in the stored body. Flagging it because the dispatch named the session-URL FORM specifically and A does not deliver that form — one line of PM ruling settles it if the form matters more than the count." }, { "question": "I hung `needs:contract-review` on card #16320 to close the split the `--pair` check reported. The dispatch told me the PR's label stays and that clearing a review gate is the seat's act; it said nothing about the card's missing half.", "options": [ "A — what I did: additive POST .../issues/16320/labels, read back, nothing stripped, pair check now exit 0.", "B — leave the split and report it, on the reading that any write to a review-gate carrier is the seat's act." ], "recommendation": "A, because hanging is fail-closed and the maintainer ruling the checker quotes is 「两边都挂好」 — a dual carrier hung in one stroke; a card without it is enqueueable straight past a gate that is demonstrably live on the PR. I did not touch the PR's label and I cleared nothing. If the seat wants the card bare, one DELETE undoes it." } ], "out_of_scope_findings": [ "noted, not filed: `listUnregisteredKindSchemaTypes()`'s docblock (packages/spec/src/kernel/metadata-type-schemas.ts) says the map holds five types 'today — webhook / connector / sharing_rule / theme / analytics_cube'; it holds FOUR (theme left at #10485, and the removal site's own comment records that). A missing/extra member in a prose list is not a filing class under my rules. 承接者: whoever fixes #17356 — that fix touches this exact file and root set, and I put the correction in my #17356 comment so it lands with it.", "noted, not filed: the changeset gate `check-adr-0087-registration` and AGENTS.md's 'a breaking changeset states FROM -> TO' convention still contradict each other on this route (measured last round: adding the house `## FROM → TO` heading flips the gate to exit 1 demanding `registered ENTRY_ID`, which the ruling forbids). Unchanged this round and already reported to PM by the previous round's report; not re-filed. 承接者: PM, as a gate-design question, not this PR." ] }
Generated by Claude Code
github-actions commented
on Sep 10, 2026 on Sep 10, 2026 – with GitHub ActionsContributorMore actionsos-closed-card-sweep — machine-findable marker for this generated comment.
Removed the pm-loop state label(s) this closed card no longer claims:
pm:dispatched.- Closing pull request: refactor(spec)!: delete the seven cron-typed positions outright — no tombstone, no D2, no D3 (#16320, ADR-0049, the 直接删 ruling) #17146, merged.
- Closing commit
929d9e3f20, merged intomain. - Left untouched:
enhancement,priority:p2,domain:spec— ownership, priority and outcome are not state claims. - The label set was read back after the write and matched.
A state label claims work is in flight. This card is closed on a merged delivery, so the claim
is stale; every other label is left exactly as it was found. Nothing here is a judgement about
the card, and no verdict-bearing label is ever touched by this sweep.posted by half-state-patrol run 34484272265 · trigger
scheduleGenerated by Claude Code
- added 5 commits that reference this issue
on Sep 17, 2026
Work card for the #15954 ruling (director seat, decision batch #56, maintainer 「其他同意」 on the per-family recommendation, 2026-09-06). This card carries the retire half; the
PromptTemplatemarking half is its sibling card (linked from #15954). Sequencing: after the #15028 / #15035 narrowing PR onshared/expression.zod.tslands.Positions to retire (seven positions, six key names)
origin/mainf1e91595f, re-locate by text)api/export.zod.tsScheduledExport.schedule.cronExpressionapi/export.zod.tsScheduleExportRequest.schedule.cronExpressionautomation/execution.zod.tsScheduleState.cronExpressionintegration/connector.zod.tsDataSyncConfig.scheduleConnector.syncConfig,defineStack({ connectors })system/cache.zod.tsCacheWarmup.schedulesystem/disaster-recovery.zod.tsBackupConfig.schedulesystem/disaster-recovery.zod.tsDisasterRecoveryPlan.testing.scheduleNot in scope:
system/job.zod.tsCronSchedule.expression(read bycroner),ai/knowledge-source.zod.tsKnowledgeRefreshPolicy.cron(experimental-marked),Object.titleFormat(read by objectui; #15947), and thePromptTemplatepair (sibling card).Shape — the #14477 / PR #15514 precedent,
spec-property-retirementplaybookRETIRED_KEYS_BY_MAJOR[18]entries +retiredKey()tombstones at each position; refusal pins (an author who writes the key gets the tombstone's did-you-mean, never silent acceptance).ScheduleState; connector sync schedule; cache warmup; backup / DR testing. The connector entry states the measured population (zero in-repo authors — examples, docs, skills, objectui pin all swept with controls; out-of-repo stacks NOT MEASURED) since it is the only stack-collection member.cron-declared-unwiredledger rows for these positions (packages/qa/dogfood/test/expression-conformance.ledger.ts).@objectstack/specminor,**BREAKING**banner,<!-- adr-0087: registered <entry-ids> -->. Immediate retirement, no deprecation window (2026-08-27 ruling).Clause-②: yeson both carriers; contract review at tier.Re-check before claiming