Skip to content

spec: route the 10 bare z.number() wall-clock instants to EpochMs (census #18078 class C ×4 + unit-nowhere instants ×6) — tranche 1 of ruling C on #18080 #18114

Closed

Description

@os-elon-musk

Filed by the director seat (objectstack #12708, summon #23, session_01WCEaPsmKY4UyoivKkkaUHt) executing decision batch #133 item 4 — maintainer 「决裁批 #133 同意」 to the recommended C on #18080, whose ruling names this as tranche 1 (the B half: instants first, because the remedy already exists in the tree and needs no gate change), 2026-09-14T03:29Z. domain:spec by landing site; p2 (silent ×1000 unit ambiguity on published keys); triage may re-rank.

The population — census #18078 @ fb29f62cee, re-verify on today's origin/main before touching anything

10 bare z.number() wall-clock instants that are not EpochMs (the census's own list; the 6 already-declared EpochMs users are the convention):

file:line key how the unit is stated today
packages/spec/src/data/document.zod.ts:35 createdAt JSDoc "(Unix milliseconds)" only
packages/spec/src/data/document.zod.ts:402 expiresAt JSDoc only
packages/spec/src/system/supplier-security.zod.ts:146 assessedAt JSDoc only
packages/spec/src/system/supplier-security.zod.ts:151 validUntil JSDoc only
packages/spec/src/identity/identity.zod.ts:111 expiresAt describe "Token expiry timestamp (Unix)" — names the epoch, not the unit
packages/spec/src/kernel/plugin-loading.zod.ts:99 timestamp nowhere (five lines above durationMs in the same object)
packages/spec/src/kernel/plugin-loading.zod.ts:154 startedAt nowhere
packages/spec/src/kernel/plugin-loading.zod.ts:159 completedAt nowhere
packages/spec/src/shared/connector-auth.zod.ts:38 tokenExpiry nowhere (the one instant INSIDE the census — it matches the expiry token)
packages/spec/src/system/supplier-security.zod.ts:188 deadline nowhere ("Remediation deadline timestamp")

⛔ Not instants, deliberately excluded by the census: system/collaboration.zod.ts:207 lamportTimestamp and :221 lamportClock — logical clocks.

What to do

Each row adopts EpochMs (packages/spec/src/shared/epoch.zod.ts, z.number().int()), keeping its own .describe() and JSDoc (the EpochMs docblock says: name the key *At; ⛔ this card does not rename keys — timestamp, tokenExpiry, deadline, validUntil keep their names; a rename is a separate retirement with its own ADR-0087 entry and is not ruled here). Where a JSDoc says "(Unix milliseconds)" it stays; where nothing says it, the describe gains the unit the type now carries.

Measurements the PR must carry (they decide the changeset shape, ⛔ not the letter)

  1. EpochMs is int(): does any first-party producer (tests, fixtures, examples, plugins) write a non-integer into any of the 10 keys? Grep + run the suites. Zero ⇒ this is alignment to a declared convention (level per AGENTS.md changeset rules, no banner). Any hit ⇒ it is a tightening that refuses a value someone writes today: **BREAKING** banner + ADR-0087 disposition per the launch-window section (level stays minor pre-GA).
  2. The gate's own summary line N declared EpochMs instant(s) reads 6 today and 16 after (acceptance reading; run tsx scripts/check-duration-unit-keys.ts --list in packages/spec).
  3. tokenExpiry leaves the census's A-class 23 (it stops being a [name: -] [prose: -] row) — record the before/after --list count.

Clause-②: the seat derives at claim. Prediction for the record: a narrowing of the accepted set on 10 published keys, no new symbol, no widening ⇒ no; if measurement 1 finds a producer, still no (tightening), but the banner applies.

Fences

  • ⛔ Durations (census classes A-true, B, D-durations) are tranche 2, gated on the definition sub-card filed alongside this one — do not touch shutdownTimeout, loadTime, saveTime, estimatedMigrationTime, resolution or any duration row here.
  • ⛔ No gate change in check-duration-unit-keys.ts; this tranche is data-only.
  • ⛔ content/docs/releases/** untouched.

Re-check before claiming

git fetch origin main && cd packages/spec
git grep -n -E 'EpochMs' origin/main -- src | wc -l            # baseline reference count
tsx scripts/check-duration-unit-keys.ts --list | grep -c 'declared EpochMs'   # the summary line exists

Confirm each of the 10 rows is still a bare z.number() at the named line (lines drift; the key + file are the identity).

Refs

#18080 (ruling C, batch #133 item 4) · #18078 (census) · #15676 (ruling B, the instants shape) · #15939 (parent epic, closed) · packages/spec/src/shared/epoch.zod.ts

Dedup terms: EpochMs, bare z.number() instant, tokenExpiry, plugin-loading timestamp startedAt completedAt, supplier-security deadline, census 18078 class C


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 17, 2026
  2. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    Claim: PM loop round 7
    Session: session_01JbZnqu8bt6YqfJsr9vaFb3
    Branch: claude/issue-18114-epochms-instants-tranche1
    Worktree: objectstack-issue-18114
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549; seat 1 is #6017 and this claim does not touch it)
    File surface: the five files carrying the ten ruled rows — packages/spec/src/data/document.zod.ts · packages/spec/src/system/supplier-security.zod.ts · packages/spec/src/identity/identity.zod.ts · packages/spec/src/kernel/plugin-loading.zod.ts · packages/spec/src/shared/connector-auth.zod.ts. ⚠️ OPEN and pre-declared: .changeset/*.md and every generated artifact a gate reverse-requires (authorable-surface/**, content/docs/references/**, api-surface/**, spec-changes.json, …) — ⛔ not a scope breach. Read-only: packages/spec/src/shared/epoch.zod.ts as the convention, and packages/spec/scripts/check-duration-unit-keys.ts as the acceptance instrument (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement tier
    Clause-②: no
    Thread-read: none
    Serial constraints cleared: measured. All 6 open domain:spec pm:dispatched threads scanned for the five files plus epoch.zod / EpochMs / migrations/registry — 0 hits on all five source files, 0 on epoch.zod, 0 on EpochMs; firing control on the same blobs: packages/spec → 115 hits, so those zeros are readings. 🚨 One hit, and it is a conditional this claim carries rather than hides — see below.


    🚨 migrations/registry.ts is held by TWO things at once — a conditional, ⛔ not a fence

    The card's measurement 1 decides the changeset shape: if any first-party producer writes a non-integer into one of the ten keys, the tranche becomes a tightening that refuses a value someone writes today, which owes a **BREAKING** banner and an ADR-0087 disposition — and an ADR-0087 entry lands in packages/spec/src/migrations/registry.ts.

    That file is currently held by two in-flight items, measured on the live board:

    ⇒ the dispatch order tells the dev: if measurement 1 fires, stop and report — ⛔ do not edit that file. ⭐ This is written as a conditional the dev resolves by measuring, ⛔ not as an assumption that it will not fire. This seat cannot run measurement 1 and so ⛔ will not pretend to know its answer.

    Premise re-verified on origin/main before claiming

    The card says its census sha fb29f62cee is stale and to re-confirm each row by key + file, not by line. Spot-checked three of the ten on today's tree (⏱️ read in the act that posted this claim, 2026-09-17T09:31Z):

    data/document.zod.ts:35      createdAt:   z.number().describe('Creation timestamp'),
    kernel/plugin-loading.zod.ts:154  startedAt:   z.number().int().min(0).optional(),      ← ⚠️ already .int().min(0)
    shared/connector-auth.zod.ts:38   tokenExpiry: z.number().optional().describe('Token expiry timestamp'),
    LIT CONTROL — files under packages/spec/src mentioning `EpochMs`   16
    

    ⚠️ startedAt is not a bare z.number() — it already carries .int().min(0). That does not refute the card (its identity is "an instant not declared EpochMs"), but it does mean the ten rows are not uniform and a mechanical sweep would mis-describe at least one of them. Handed to the dev as a per-row re-derivation, ⛔ not as a fence.

    Clause-②: no — derived here, and it agrees with the card's own prediction

    Adopting EpochMs (z.number().int()) on ten already-published keys narrows the accepted set; it adds no exported symbol, no new key on any published payload, and no registry row. Clause ② polices the widening direction. ⇒ no. The card predicted the same and said the seat derives at claim — this is that derivation, ⛔ not a copy of the prediction.

    The ruling this executes — ⛔ not re-openable

    Director seat, decision batch #133 item 4, maintainer verbatim 「决裁批 #133 同意」 to recommendation C on #18080, which names this as tranche 1. Fences ruled with it: durations are tranche 2 (⛔ untouched here), ⛔ no gate change, ⛔ content/docs/releases/** untouched, ⛔ no key renamed.

    Dedupe

    MCP search_issues over open and closed: 2 results — this card, and #13801 (the duration half, a different ruling half and explicitly tranche 2 territory). ⛔ No twin.


    Generated by Claude Code

  3. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    os-dev-report
    {
    "issue": 18114,
    "status": "done",
    "branch": "claude/issue-18114-epochms-instants-tranche1",
    "pr": "#18631",
    "session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
    "premise_still_valid": true,
    "summary": "All ten wall-clock instants now declare their unit through the shared EpochMs schema; no key renamed, gate script untouched, migrations/registry.ts untouched. Two corrections to the card, both re-derived on the branch point 559041d and carried in the PR body. (1) THREE rows are not bare z.number() — kernel/plugin-loading.zod.ts timestamp, startedAt and completedAt already carried .int().min(0) (the seat spot-checked startedAt; the other two are the same shape). They adopt EpochMs.min(0), because EpochMs deliberately declares no .min() and a bare adoption would have DROPPED the floor and newly accepted negative instants on three published keys — a widening, the exact direction Clause-②: no denies. Their JSON Schema is unchanged apart from the new description; the other seven move from type number to type integer. (2) The acceptance base reading is off by one: the gate reads 5 declared EpochMs instant(s) before, not 6, and 15 after, not 16. The delta is exactly the ruled plus ten. There is no sixth pre-existing adopter in the tree — the five are websocket occurredAt/lastSeenAt, context startedAt, service-registry registeredAt/createdAt. Measurement 1 found ZERO non-integer first-party producers, so the changeset is the alignment shape: @objectstack/spec minor, no BREAKING banner, no ADR-0087 disposition, and registry.ts was not opened — the branch the card told me to stop and report on did not fire. The assignee field was already set by the dispatch (os-bill) and I did not touch it; the newest Claim: names this branch.",
    "tests": "ALL GREEN unless named. Acceptance readings, tsx scripts/check-duration-unit-keys.ts --list in packages/spec: BEFORE at 559041d '185 unit-declaring numeric key(s) ... 5 declared EpochMs instant(s)'; AFTER at 597bb75 '195 unit-declaring numeric key(s) ... 15 declared EpochMs instant(s); zero offenders, no baseline'. MEASUREMENT 1 (method, not just verdict): (a) grepped the 8 enclosing schema names plus distinctive sibling keys (versionNumber, assessedBy, overallCompliant, requirementId, tokenExpiry, sharedWith) repo-wide — outside packages/spec only generated reference pages and surface snapshots; the sole first-party producers are spec's own tests; (b) read every value they write (1704067200000, 1735689600000, 1767225600000, 1700000000, Date.now(), Date.now() plus 3652460601000, Date.now() plus 3600000) — all integers; (c) repo-wide fractional sweep over the nine key names WITH A POSITIVE CONTROL: exactly one hit, packages/spec/src/kernel/context.test.ts:90 'startedAt: 1.5', which is the refusal pin on a key that is ALREADY EpochMs — so the instrument does find a fractional write when one exists, and found no producer; a second sweep for performance.now()/Math.random() into those keys returned nothing; (d) suites: pnpm --filter @objectstack/spec test = 485 files / 13837 tests passed post-merge (13819 pre-merge). MEASUREMENT 3 is PART NOT MEASURED and reported as such: 'tokenExpiry stops being a [name: -] [prose: -] row' is unmeasurable on this instrument — --list printed ZERO such rows before the change, so tokenExpiry was not one and could not leave; the A-class 23 belongs to census #18078, a different instrument. Measured instead: tokenExpiry was ABSENT from --list before (no unit in name, type or prose = not admitted) and after is 'connector-auth.zod.ts:39 tokenExpiry [name: -] [prose: ms] [instant: EpochMs]'. The [name: -] [prose: -] row count moves from 0 to 4 (document createdAt/expiresAt, supplier-security assessedAt/validUntil — the four whose describe deliberately stays unit-free because their JSDoc already says '(Unix milliseconds)'). RED BEFORE GREEN: (i) check:docs observed red — check:generated at the implementation commit printed 'x 1 of 15 artifact(s) stale: content/docs/references/**' exit 1, green after gen:docs ('All 15 generated artifacts are up to date', exit 0). (ii) check:duration-unit-keys is green both before and after, so it was ABLATED to prove it reaches the new sites: mutated connector-auth tokenExpiry's describe to name seconds; anchor grep counts went orig=1/mut=0 to orig=0/mut=1 and the on-disk blob went 747bb855f3e0 to a1723e069fea, proving the mutation landed; RUN A exit 1 with '[instant-unit-contradicts-schema] packages/spec/src/shared/connector-auth.zod.ts:39 tokenExpiry — typed EpochMs (epoch MILLISECONDS) but the describe says seconds'; restored with git checkout HEAD -- PATH under a trap ... EXIT INT TERM using absolute paths, restore proven by blob-hash identity with the HEAD blob and an empty git diff HEAD (not by an exit code); RUN B exit 0. Expected direction was 'turns red' and that is what was observed. No dist preflight applies — the gate is a TypeScript SOURCE AST scan, so the on-disk byte proof is the reachability proof; no test file left behind. GATES: 95 commands derived by 'node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack' (it derived the change set itself from the merge base) were run; 94 exit 0. Card-named, all green: check:generated (All 15 up to date), check:authorable-surface (1538 schemas), check:api-surface ('public API surface + factory signatures unchanged' — the load-bearing consumer reading: z.input of EpochMs is number, so no published TypeScript type moves and no importing package owes a re-measure), check:docs (224 generated files in sync), typecheck (incl. check:scripts-typecheck and check:test-typecheck), and 'node scripts/pm/check-widening-tells.mjs --declaration no --diff PRDIFF' = '10 changed file(s) — 5 judged against a declared surface (no widening tell), 5 NOT MEASURED' (the 5 generated .mdx, no declared surface covers them). Repo-wide 'eslint . --no-inline-config' actually RAN and is clean: 6809 files judged from eslint's own config, 0 errors, 0 warnings, exit 0, at 597bb75 — a full run, so no narrowing argument is needed; the config states in its own comment that this repo never enables type-aware linting. NOT MEASURED (1): pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET — needs a full repo build (26 or more connector packages have no dist/ here); neither a pass nor a failure, CI owns it. Five siblings that first reported the same exit 3 / not-built code (check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift, check:lean-entry-closure) were converted into REAL readings by building @objectstack/lint, @objectstack/formula and @objectstack/client-react, and all five are green. ONE RED NOT CAUSED BY THIS DIFF: pnpm check:cross-package-test-inputs exits 1 in this worktree — see out_of_scope_findings item 1 for the two-legged control that proves it is build-state dependent. MERGE: origin/main moved during the run (build-schemas.ts, PR #18618, is in it), so I merged via 'bash scripts/pm/os-regen-merge.sh', rebuilt spec and re-ran check:generated (all 15 up to date — no joint wrongness), then re-took the acceptance reading, typecheck, tests and eslint at the post-merge HEAD 597bb75. All numbers quoted here are that HEAD except the explicitly labelled BEFORE reading. CI convergence is not waited on: gate status as of the report is as printed above.",
    "mcp_calls": "0 — no MCP GitHub tool was called, read or write. Every GitHub interaction went through the REST proxy with curl.",
    "api_writes": "3 REST writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18631); POST /repos//issues/18631/labels (additive endpoint, domain:spec plus priority:p2, http 200, comparative read-back shows none stripped); POST /repos//issues/18114/comments (this report). Plus 3 git pushes to the feature branch (empty-branch routing probe, implementation, changeset plus merge). No PATCH of any body. needs:contract-review is ABSENT from PR #18631 and I neither added nor removed it — 'node scripts/pm/check-clause2-carriers.mjs --pair 18631' exits 0: 'the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell'.",
    "open_questions": [
    {
    "question": "The three kernel/plugin-loading rows already declared .int().min(0), which the card did not anticipate. I wrote them EpochMs.min(0) so the accepted set is unchanged. Is preserving the site's own floor the shape the ruling wants, or should an instant that adopts EpochMs shed .min(0) to match the shared schema exactly?",
    "options": [
    "A — keep EpochMs.min(0) (what this PR ships): the accepted set on the three published keys is byte-identical to before, only the description is new; nothing widens, so Clause-②: no stands unqualified. EpochMs's own docblock sets the precedent ('the four that already declared .int() keep exactly what they had'), and the gate recognises the chain root through .min(), proven by the [instant: EpochMs] rows and the ablation.",
    "B — write a bare EpochMs on all ten: uniform with the other seven and with the shared schema's stated position that a pre-1970 instant is legitimate, but it DROPS .min(0) and newly accepts negative values on PluginLoadingEvent.timestamp, PluginLoadingState.startedAt and .completedAt. That is a widening on three published keys and would make Clause-②: no false for this PR, needing its own declaration and probably its own card."
    ],
    "recommendation": "A, because it is the only arm that keeps this tranche a pure unit DECLARATION. The ruling's remedy is 'the instant declares its unit'; changing what values three published keys accept is a separate decision with a separate direction, and B would have to be argued on its merits (is a negative plugin-load timestamp meaningful?) rather than arriving as a side effect of a documentation-shaped change. If the seat prefers B, it is a one-line-per-key follow-up with its own Clause-② line, not a correction to this one."
    }
    ],
    "out_of_scope_findings": [
    "to file (3 classes: (a) reproducible defect; dedupe words: check-cross-package-test-inputs, walked root, packages/spec/dist, init-created-files-summary.e2e.test.ts, ACCEPTED_WALK_RADII, build-state dependent gate verdict) — pnpm check:cross-package-test-inputs decides one verdict from a GITIGNORED directory's presence on disk rather than from tracked source: where packages/spec/dist/ exists it exits 1 flagging @objectstack/cli's walk from packages/spec/dist/ as reached by no declared glob, and on the identical source without it, exit 0. Two-legged control, each an unbuilt worktree running 'node scripts/check-cross-package-test-inputs.mjs' directly: branch point 559041d exits 0 and this branch's own HEAD exits 0 — then 'mkdir -p packages/spec/dist/probe-subdir' plus one file in that same clean tree flips it to exit 1 with the byte-identical finding. So a contributor who builds spec before running the gate sees a red a fresh checkout never shows, and the reverse hides it. Not mine to fix and not in this PR.",
    "noted, not filed: packages/spec/src/shared/connector-auth.test.ts:32 writes 'tokenExpiry: 1700000000' — Nov 2023 read as SECONDS, 20 Jan 1970 read as milliseconds. An integer, so not a measurement-1 hit and the schema cannot tell them apart; it is evidence the x1000 ambiguity this card closes was live in the tree rather than theoretical. The describe now says milliseconds, so the trap is shut at the contract. Successor: whoever next edits that fixture — this PR leaves the file untouched because it is outside the claim's declared file surface and changing it would measure nothing.",
    "noted, not filed: EpochMs's docblock recommends spelling an instant *At and four of the ten keys do not (timestamp, tokenExpiry, deadline, validUntil). The card rules a rename out — it is a retirement with its own ADR-0087 entry. Successor: named and already scoped by the ruling on #18080, so not a loose end."
    ]
    }


    Generated by Claude Code

  4. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ACCEPT — PR #18631。domain:spec seat 2(session_01JbZnqu8bt6YqfJsr9vaFb3,座位贴 #18549),R7。⏱️ 本条读数取自同一动作:2026-09-17T10:25Z。对 GitHub 与树核验,⛔ 不对终报自述核验。

    形态与范围

    GET /pulls/18631:draft: true · base: main · head 597bb75a13(⏱️ 取数时刻 = 本评论 created_at,API 实读:2026-09-17T10:25:28Z —— H44 back-fill) · changed_files: 11 · +48 −24。首行 Fixes #18114(全文仅此一处);1 个页脚。

    🚨 packages/spec/src/migrations/registry.ts 不在文件清单里 —— 本席派发令里那个「若测量 1 发现非整数生产者就停下回报、⛔ 不碰该文件」的条件没有触发,因为测量 1 读到 0。⇒ 与 PR #18619 / 席 1 #17534 的三方碰撞没有发生。⛔ 其余持有文件也一个没碰(view.zod.ts · build-schemas.ts · contracts/automation-service.ts)。

    树上核验(head 597bb75a13,⛔ 非终报叙述)

    plugin-loading.zod.ts:100  timestamp:   EpochMs.min(0).describe(…)
    plugin-loading.zod.ts:155  startedAt:   EpochMs.min(0).optional()…
    plugin-loading.zod.ts:160  completedAt: EpochMs.min(0).optional()…
    document.zod.ts:36/403 · identity.zod.ts:112 · connector-auth.zod.ts:39
    supplier-security.zod.ts:147/152/189                    ← 其余七条裸 EpochMs
    changeset  "@objectstack/spec": minor · **BREAKING** 计 0 · adr-0087 marker 计 0
    

    ⭐ 两处对卡面的更正,都由 dev 测出来,都对

    1. 不是一行而是三行已经带 .int().min(0)(timestamp / startedAt / completedAt)。本席派发时只抽验了十行里的三行、并明写「另七行未读、十行并不齐整、请逐行重导」—— 那个旗正是这么用的,dev 顺着它把另外两行找了出来。
    2. 验收基线读数卡面写错了一个:门禁读的是 5 → 15,不是 6 → 16;增量恰好是被裁的十条,树上不存在第六个既有 adopter。⇒ 卡面 measurement 2 的数字有误,记在这里,免得下一个人照抄。

    🚨 .min(0) 这一步是本 PR 最要紧的判断,而且方向正确

    EpochMs 是 z.number().int() 且故意不带 .min()(其 docblock:pre-1970 的负值是合法的)。⇒ 把那三行写成裸 EpochMs 会丢掉 .min(0),于是三个已发布键新接受负值 —— 那是放宽,正是 Clause-②: no 否认的方向。dev 写成 EpochMs.min(0),接受集逐字节不变、只有描述是新的。

    ⇒ 待答问题取 A,理由与终报一致并加一条:本 tranche 的裁定措辞是「让时刻声明它的单位」,而改变三个已发布键接受什么值是另一个方向的决定,⛔ 不该作为一次文档形改动的副作用到达。若日后要取 B,那是一张带自己 Clause-② 行的独立卡,⛔ 不是对本 PR 的更正。

    ⭐ 值得记的两条方法

    ⚠️ 本席的仪器又坏了一次 —— 同一个变体的第四次

    本席读 PR 正文找 Clause-② 行时用了 line.strip().startswith('Clause-②'),读成 MISSING;正文里那行是 `Clause-②: no` —— 被反引号包着。官方读者 readClause2Line 正确识别,--pair 18631 exit 0。
    ⭐ 本席自纠清单第 3 条原文就写着「三次被自己的坏探针骗(反引号包裹、折行、平文本短语)」。同一变体的第四次。 ⇒ 纪律收紧:读一个有官方读者的字段,就调那个读者,⛔ 不要自己再写一个。

    out_of_scope_findings

    check:cross-package-test-inputs 依 packages/spec/dist 是否存在给相反判决 —— 这是本班第三个 dev 独立撞上它,而且这次带了两条腿的对照(同一棵干净树里 mkdir packages/spec/dist/probe-subdir 就能把 0 翻成 1)。⛔ 仍不立孪生:已有 #18353 / #18440。另两条终报自标 noted, not filed 并各自点名后继,⛔ 本席不代立。


    CI 在 head 597bb75a13 上尚有 16 个 job 在跑(0 红)。本卡 Clause-②: no ⇒ ⛔ 不欠达档复核;落地前检三条待 CI 收敛后当场实跑。

    ⚠️ 一条要在落地前检里特别做的:dev 在运行中用 scripts/pm/os-regen-merge.sh 合过一次 origin/main(PR #18618 落在了中间),而本 PR 的五张生成参考页都在 merge=os-regen 清单上 ⇒ 入队前与落地后都要验生成物没被吞。


    Generated by Claude Code

  5. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    落地前检 —— 本分钟实跑,⛔ 无一条凭记忆

    ⏱️ 全部读数取自本评论同一动作:2026-09-17T10:44Z。

    check result
    check-governed-merges --pr 18631 exit 0 — 0 of 11 path(s) 命中受管册 ⇒ NOT governed
    check-clause2-carriers --pair 18631 exit 0
    check-expected-skips --pr 18631 exit 0 — 43 runs:35 success · 8 skipped · 0 other
    CI on head 597bb75a13 0 in progress,0 red

    本卡 Clause-②: no ⇒ ⛔ 不欠达档复核,落地前检 ① 不适用。

    🚨 os-regen —— 本 PR 5 条路径在清单上,而且 dev 中途合过一次 main

    五张生成参考页(data/document · identity/identity · integration/connector · kernel/plugin-loading · system/supplier-security)全在 merge=os-regen 清单上。⚠️ 更要紧的是 dev 在运行中用 scripts/pm/os-regen-merge.sh 合过一次 origin/main(PR #18618 落在了中间),所以「入队前查一次」在这条分支上尤其不能省。

    PR base sha                                   7f4aa9e5c3
    origin/main 现 tip                            00115a8442
    base..origin/main 触及 content/docs/references  0 commits
    LIT control — base..origin/main 全部 commits     1 commit
    

    ⇒ 亮控给了 1,所以那个 0 是「main 走了一步但没碰这五张页」,⛔ 不是空仪器。分支点之后没有可被吞的另一侧,四步序无事可做。
    ⚠️ 落地后还要再验一次 —— 队列的合并同样走 os-regen,入队前干净 ⛔ 不等于落地后干净。

    入队

    ready_for_review → {"draft":false};复读到 draft:false / mergeable:true / mergeable_state:clean 落定后挂 auto-merge → {"enabled":true}。效果读数:timeline added_to_merge_queue = 1。已入队,跟到 origin/main 上的 squash + 单亲为止。


    Generated by Claude Code

  6. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    巡检 H52 —— 那条 open_questions 已答(取 A),本卡 ⛔ 不欠 needs-user-decision

    ⏱️ 巡检读数取自本评论同一动作:2026-09-17T11:01Z。

    半状态巡检报:终报(5712776453)带 1 条非空 open_questions,而本卡没有 needs-user-decision 标。

    那条问题是:三行 plugin-loading 已带 .int().min(0),写成 EpochMs.min(0)(保住地板)还是裸 EpochMs(与共享 schema 一致但丢掉地板)?

    ⇒ 已在 ACCEPT 5712818998 里取 A,理由两条:①裸 EpochMs 会让三个已发布键新接受负值 —— 那是放宽,与本 PR 的 Clause-②: no 直接矛盾;②本 tranche 的裁定措辞是「让时刻声明它的单位」,改变已发布键接受什么值是另一个方向的决定,⛔ 不该作为一次文档形改动的副作用到达。

    ⇒ ⛔ 不挂 needs-user-decision —— 答案已定,且 dev 交付的就是 A。若日后要取 B,那是一张带自己 Clause-② 行的独立卡,⛔ 不是对本 PR 的更正。

    同轮另两行


    Generated by Claude Code

  7. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ✅ MERGED —— 十个挂钟时刻现在自己声明单位

    ⏱️ 本条读数取自同一动作:2026-09-17T11:04Z。

    reading value
    squash commit 25c9a8317b — feat(spec): the ten bare wall-clock instants adopt EpochMs (tranche 1 of ruling C on #18080) (#18631)
    parents 单亲
    method git log --oneline origin/main | grep -F '(#18631)',⛔ 非 --grep、⛔ 非 API merged

    主题探针 —— 亮控 ×3 + 暗控 ×3

    LIT   三行 plugin-loading 保住地板 EpochMs.min(0)                3
    LIT   其余七条裸 EpochMs                                         7     ⇒ 合计 10,与裁定的十条相符
    LIT   参考页 plugin-loading.mdx 出现 millisecond                  4
    DARK  落地 commit 触及 migrations/registry.ts(必须 0)            0   ⭐
    DARK  落地 commit 触及 view.zod.ts / build-schemas.ts(必须 0)    0
    DARK  伪造 token(必须 0)                                         0
    

    ⭐ 第一条暗控是本席派发时那个条件的结算:派发令写了「若测量 1 发现非整数生产者,就要补 ADR-0087 条目 → 落在 migrations/registry.ts,而那个文件同时被 PR #18619 与席 1 的 #17534 持有 ⇒ 停下回报,⛔ 不碰它」。测量 1 读到 0 个非整数生产者,于是那一支没触发;落地 commit 里该文件读 0 ⇒ 三方碰撞在树上确实没有发生,⛔ 不只是评审时的承诺。

    🚨 os-regen 落地后再验一次

    本 PR 的五张生成参考页全在 merge=os-regen 清单上,而且 dev 在运行中用 os-regen-merge.sh 合过一次 main(#18618 落在中间)⇒ 入队前查过 ⛔ 不等于落地后成立。落地 commit 的文件清单读回 11 个,五张参考页一张不少;另四张页的行数非零且完整(document=149 · identity=86 · connector=958 · supplier-security=139)。队列没有静默吞边。

    收口

    全文扫闭合关键词:只有 Fixes #18114 一处,无 Part of。卡 closed / completed,pm:dispatched 已摘(标签联合先读回再整组写)。

    卡面两处数字更正,留给后来人

    ① 「一行已带 .int().min(0)」 ⇒ 实为三行(timestamp / startedAt / completedAt)。② 门禁验收基线是 5 → 15,⛔ 不是卡面写的 6 → 16。

    待答问题取 A(见 5712818998 与 5713255005)

    三行写 EpochMs.min(0) 保住地板:裸 EpochMs 会让三个已发布键新接受负值 —— 那是放宽,与本 PR 的 Clause-②: no 直接矛盾。若要取 B,那是一张带自己 Clause-② 行的独立卡。


    Generated by Claude Code

  8. added a commit that references this issue on Sep 28, 2026
    25c9a83
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions