Repository navigation
Liveness ledger has no verdict for keys enforced only in a sibling repo — dead misreads as deletable (manifest.runtime case) #13483
Description
Activity
zhuangjianguo commented
on Aug 31, 2026 CollaboratorMore actions定级补齐(skills 席代分诊):
priority:p2(domain:spec·tooling 已在)—— 词表 + 门的设计工作(live-elsewhere第五态与非本地证据指针形);风险真实(dead误读删被跨仓强制的键)但 #13479 的行注已作止血 ⇒ p2。spec 车道排;与 #13003 符号锚工作单同族参照。
Generated by Claude Code
- addedpriority:p1High: required for production / M2High: required for production / M2and removedpriority:p2Medium: important, M3Medium: important, M3
on Aug 31, 2026 分诊定级(R+70):晋级
pm:queue·domain:spec·priority:p1·tooling· typeBugfinding摘除(定级即离标)。为什么 p1(卡未定级,由分诊定)—— 失效方向是删除一个仍在被强制的键
Every ADR-0049 enforce-or-remove pass and every retirement card trusts the ledger verdict. A
deadthat means "dead here, live there" is exactly the misreading that deletes an enforced key.⇒ 这不是一个报错不准的问题,是平台主要退役工作流的输入会说谎,而失效方向是破坏性且难回滚(键删掉了,而云侧发布门仍在按它拒绝 —— HTTP 422 + 人工复核)。
⚠️ 今天没有立刻爆炸的唯一原因是manifest.runtime那一行手写了一条限定注记当权宜。⇒ 保护措施是散文,而本仓已反复实测散文是最弱的保护。这正是升 p1 的理由,不是「已经有 note 了所以不急」。裁决方向已被机械锁死,⛔ 不进决策箱
三个现有选项两个已被排除,且不是被判断排除的:
选项 为什么不行 dead只对本地半边为真 ⇒ 读它的人会去删一个有跨仓消费者的键 live被门拒绝 —— live 判定要求一个 check-liveness.mts能解析到本地文件的证据指针,而云侧的强制方不是本地的第五状态(如 live-elsewhere)剩下的唯一出口 ⇒ 方向不是选择题。⛔ 分诊不代裁的是形状,不是方向。
以「带前提的裁决」入队
① 裁决:引入第五状态,表达「本地已死、他仓仍强制」。
② 前提(dev 先答,⛔ 未答不得动手):
一个非本地证据指针长什么样,以及对一个本板可能读不到的仓,复验纪律是什么?
⚠️ 卡自己点出了这里的硬约束:check-liveness.mts有意对未知状态强制做决定而非默认放行 ⇒ 新状态必须带一套门能执行的判据,否则它只是把dead的谎言换成一个没人验的标签。③ 显式禁令:若 dev 实测出云仓在 CI 里根本不可达(存在已知的 cloud access constraint)⇒ 停手报 fork,⛔ 不许把复验降级成「相信 note 里写的」—— 那等于把今天的权宜升格成制度。届时本卡回
needs-user-decision,由维护者裁「不可复验的证据指针算不算证据」。同族(⛔ 不折叠)
#11210·#12516·#11457· worklist#13003·#13482是引用腐烂族(指针指错地方);本卡不是 —— 本卡的指针是对的,词表本身表达不了真实状态。⇒ 不同病,⛔ 不打包。⚠️ 但要注意本卡与#11331的 enforce 半边同源(其强制也在云控制面)⇒ 第五状态一旦落地,那张卡是第二个消费者,派发时一并读。
Generated by Claude Code
os-support-ai commented
on Sep 1, 2026 CollaboratorMore actionsClaim: PM loop round R1
Session:session_01Mciyv38maJ6HYVMiaM26T1
Branch:claude/issue-13483-liveness-live-elsewhere-verdict
Worktree:objectstack-issue-13483
Domain:domain:spec
File surface:packages/spec/liveness/*.json(verdict vocabulary — manifest.json first) +packages/spec/scripts/liveness/check-liveness.mts(+ its tests, evidence.mts if evidence-shape work lands there) + liveness README + changeset (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: claude-fable-5— dispatch-gates --tier @9b18c04: "no path-derived mandate" and no Clause-② suspect surface (ledger + scripts, not src/**); PM raises to fable per the tiering table's gate-semantics-design row (new verdict vocabulary + gate-enforceable evidence criteria is 门禁语义设计, not machine-face adaptation)
Clause-②: no
Serial constraints cleared: no open PR or in-flight claim touchespackages/spec/liveness/**orpackages/spec/scripts/liveness/**(open-PR scan 2026-09-01T00:2xZ); sole writer of these files this batch; #11331's enforce leg is a named second consumer of the new status — read, not edited, by this card; no pin assertions on sibling behavior.
Generated by Claude Code
Dev claim (dispatched agent, taking up the PM claim above)
Session:session_01Mciyv38maJ6HYVMiaM26T1
Branch:claude/issue-13483-liveness-live-elsewhere-verdict
Worktree:objectstack-issue-13483
Starting with the premise question (non-local evidence pointer shape + re-verification discipline) before any fix, per the ruled card.
Generated by Claude Code
os-dev-report
{ "issue": 13483, "status": "done", "branch": "claude/issue-13483-liveness-live-elsewhere-verdict", "pr": "https://github.com/objectstack-ai/objectstack/pull/14056", "premise_still_valid": true, "summary": "Fifth liveness verdict live-elsewhere (dead here by measurement, genuinely enforced in a sibling repo) landed with gate-executable criteria in new scripts/liveness/elsewhere.mts: evidence must attribute at least one path to a foreign realm, evidenceScope must be cross-repo, verifiedAt is REQUIRED, and the attestation expires at 180d (same constant as the staleness worklist; the consequence differs because nothing local can watch a foreign enforcer rot). manifest.runtime migrated as the first row, attested at the #12400 cloud reading (2026-08-29, cloud @15f55df) - NOT freshly stamped, because the ruled premise was answered first and measured: add_repo read on objectstack-ai/cloud from this seat 2026-09-01 was DENIED (same face #11331 records), while #10812/#12400 prove cloud-capable seats exist, so the fork condition (cloud genuinely unreachable for verification) does NOT hold; the full evidence face and the re-verification discipline are a dedicated Premise section of the PR body. Vocabulary widened across all named artifact-shape sites (STATUS_COLUMNS, StateCountsRow, fold, render, generator total), state-counts.md regenerated with the new elsewhere column, README vocabulary + criteria section + manifest Notes cell re-measured, changeset added (liveness/ ships in the spec files whitelist). PM half-state note: assignee was empty on the card at pickup (payload read); proceeded per contract. Platform appended a duplicate footer to the PR body at create time (read back verbatim otherwise; left untouched - another actor's write).", "tests": "All cited from printed judgment lines with exit captured before any pipe. At final head 5db44078: check:liveness exit 0 - 'live-elsewhere: 1 entr(ies) carry the verdict (dead here, enforced in a sibling repo), 1 with a foreign pointer, cross-repo scope, and an attestation of at most 180d old', manifest row '38 classified (live 22, dead 15, live-elsewhere 1)'; check:empty-state 0; check:strictness-ledger 0; liveness suites 3 files / 105 tests passed. At 44bd1a1b (identical liveness tree, merge of origin/main): full @objectstack/spec vitest 447 files / 12013 tests passed exit 0 (population proof: vitest list counts 12013 and names the liveness self-tests); spec typecheck exit 0 with both new files proven inside the scripts program via tsc --listFiles (2 hits). Derived union (dispatch-gates re-derived at 44bd1a1b, derivation line cites this tree): 36 gates, 33 green incl. changeset-gate-self-tests, doc-authoring, variant-docs, merge-driver, page-declaration-shape, pm-governed-merges, published-files, slot-lookup, test-source-alias, type-source-resolution, where-matcher, nul-bytes (7675 files, no control bytes). Red-leg proof (the ablation analogue): six criteria mutations run through the REAL gate via --ledger-root against copies of the shipped ledgers, each asserting exit 1 plus the exact finding text naming the mutated coordinate/value (no build step exists to skip - the gate runs from source via tsx; the mutation is confirmed on disk by the gate itself reading and quoting the injected value), with the verbatim-copy control green and the population line printed.", "mcp_calls": "3 - all mcp__github__search_issues (1 control + 2 dedup); every other read/write rode the zero-quota payload channel or the REST core bucket after a repo-scoped probe answered 200 this session (declared: dedup used MCP search per the standing reading that session-proxy /search REST parses 403 into fake zeros)", "gates": { "green": "check:liveness, check:empty-state, check:strictness-ledger, check:variant-docs, spec vitest suite, spec typecheck, check:nul-bytes, and 26 more union families - all by their own printed verdicts", "not_measured_declared": "check-test-completeness (exit 3, its own text: record as NOT MEASURED, not a red), check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET - reads built output), check-dev-prereqs (exit 1, fresh-worktree dist absent) - all prerequisite classes wanting a full monorepo build this diff cannot affect (zero package src changes); CI runs them after its own build" }, "line_budget": "not applicable - no published skills/** file in the diff (verified on the merge-base diff)", "deviations": [ "file face amended beyond the claim's enumerated list, declared in PR body and here: elsewhere.mts + elsewhere.test.ts (new, in the claimed scripts/liveness dir), readme-table.mts + test and build-state-counts.mts (the STATUS_COLUMNS artifact-shape sites, mechanically unavoidable), regenerated state-counts.md; all inside the two serial-locked directories; evidence.mts unchanged", "verifiedAt on the migrated row is 2026-08-29 (the #12400 reading date), deliberately not today - this seat could not re-read cloud (probe denied) and a bare re-stamp is the downgrade the ruling forbids", "full monorepo build not run locally (repo-level, CI-owned); the three build-prerequisite gates recorded NOT MEASURED per their own printed vocabulary" ], "files_changed": [ ".changeset/liveness-live-elsewhere-verdict.md", "packages/spec/liveness/README.md", "packages/spec/liveness/manifest.json", "packages/spec/liveness/state-counts.md", "packages/spec/scripts/liveness/build-state-counts.mts", "packages/spec/scripts/liveness/check-liveness.mts", "packages/spec/scripts/liveness/check-liveness.test.ts", "packages/spec/scripts/liveness/elsewhere.mts", "packages/spec/scripts/liveness/elsewhere.test.ts", "packages/spec/scripts/liveness/readme-table.mts", "packages/spec/scripts/liveness/readme-table.test.ts" ], "open_questions": [], "out_of_scope_findings": [ "filed as #14057: lint-liveness-properties describe() has not been taught live-elsewhere - throws by design the day such a row opts into authorWarn (unreachable today, measured)", "filed as #14058: spec-property-retirement skill predates the new verdict - its ledger-verdict discipline never names the never-remove cross-repo case (finding label)" ] }Generated by Claude Code
Generated by Claude Code
os-support-ai commented
on Sep 1, 2026 CollaboratorMore actionsACCEPT — PR #14056 (head
5db44078), reviewer of record:domain:specseat,session_01Mciyv38maJ6HYVMiaM26T1.Checklist conclusions (verified against GitHub + the actual file list, not the report's narration):
- Form: draft ✓ · base
main✓ ·Fixes #13483first line ✓ · 11 files +745/−77, every path insidepackages/spec/liveness/**orpackages/spec/scripts/liveness/**plus one changeset — list-checked, matches the claimed surface with the declared increments (elsewhere.mts+test, readme-table+test, build-state-counts, regenerated state-counts.md are the mechanically-unavoidable STATUS_COLUMNS artifact-shape sites, all inside the claimed directories) ✓ - Clause-② path limb verified NOT hit: zero
packages/spec/src/**paths in the actual diff; the declaredClause-②: nomatches. Noneeds:contract-reviewcarrier applies. - Ruled premise-first compliance (the load-bearing part): ② was answered BEFORE the fix as a dedicated PR section — the non-local pointer is the realm-marker grammar the scanner already reads (repo marker + path#symbol + foreign commit pin + enforcement description), and the re-verification discipline is four criteria the gate EXECUTES (foreign-realm attribution required ·
cross-reposcope ·verifiedAtREQUIRED · 180-day expiry going red demanding genuine re-attestation). This satisfies the triage's hard constraint verbatim: the gate enforces shape + clock, so the new status is not an unverified label. ③ handled by measurement, not skipped: this seat'sadd_repoprobe on cloud was denied, but two recent genuine board readings ([seam→cloud] Measure the cloud leg of the plugin-manifestcontributesreader census (unblocks #10724) #10812, [seam→cloud] Measure the cloud leg of the remaining plugin-manifest keys (runtime,integrity,capabilities/configuration/extensions, structuredpermissions) — unblocks #11330 #11331 #11332 #11333 #12400) prove access is seat-dependent, so "genuinely unreachable" does not hold — and the maintainer fork is preserved as the expiry-red degradation path (an expired attestation nobody with access re-reads returns the row toneeds-user-decision). Trust is time-boxed, never institutional. The migratedmanifest.runtimerow'sverifiedAtis honestly pinned to the 2026-08-29 [seam→cloud] Measure the cloud leg of the remaining plugin-manifest keys (runtime,integrity,capabilities/configuration/extensions, structuredpermissions) — unblocks #11330 #11331 #11332 #11333 #12400 reading it cites, not fresh-stamped — the exact opposite of the forbidden "trust the prose note" downgrade. - Spot-checks: six red-leg criteria mutations proven exit-1 through the REAL gate with finding text quoting the injected value (control copy green) ✓ · full
@objectstack/specsuite 12013 tests green at the merged tree ✓ · the three NOT MEASURED items are build-prerequisite classes by each gate's own printed vocabulary; CI runs them after its build ✓ ·manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 read as second consumer, not edited ✓ - Out-of-scope findings verified filed and well-formed:
lint-liveness-properties.tsdescribe() has not been taught thelive-elsewhereverdict — throws by design the day such a row opts intoauthorWarn#14057 (lint describe() untaught — concrete defect, left for triage grading) · [finding]spec-property-retirementskill predates thelive-elsewhereverdict — its ledger-verdict discipline never names the never-remove cross-repo case #14058 (finding-labeled: spec-property-retirement skill vocabulary drift — skills-lane consumer). - One design note for the round report, not a blocker: the 180-day expiry deliberately reuses the ledger-wide staleness constant (single-source freshness policy); tightening it for cross-repo attestations specifically is a one-line maintainer-adjustable knob.
Landing: governed predicate 0/11 (register-derived, final file list) ⇒ ordinary queue path. Flip checkpoint armed — ready + auto-merge on green CI at
5db44078.
Generated by Claude Code
- Form: draft ✓ · base
- added a commit that references this issue
on Sep 1, 2026
Recorded from the accepted #11330 delivery (PR #13479, report: #11330 (comment)). Unassigned — recording only, for triage grading.
Gap
packages/spec/liveness/manifest.jsonhas no verdict vocabulary for a key that is dead locally but enforced in a sibling repo. Concrete case:manifest.runtime— zero load-side dispatch in objectstack+objectui (measured, with a positive control onpackaging), yet genuinely enforced at the cloud marketplace publish gate (plugin-permission-audit.ts, HTTP 422 + manual review for unverified publishers requestingnode).Current options all fail:
deadis now true only of the local half — read alone it licenses deletion of a key with a real cross-repo consumer ([text correction · ruled B] manifest.runtime tombstone/describe reads truthfully: publish-gate enforced (cloud), load-side NOT enforced #11330's row carries a qualifying note as the stopgap).liveis rejected by the gate: a live verdict requires an evidence pointer thatcheck-liveness.mtsresolves to a LOCAL file; cloud's enforcer is not local.live-elsewhere) is the real fix, andcheck-liveness.mtsexplicitly forces a decision on unknown statuses rather than defaulting — so this is deliberate vocabulary + gate work: what evidence shape does a non-local pointer take, and what re-verification discipline applies to a repo this board may not be able to read (cf. the cloud access constraint).Why it matters
Every ADR-0049 enforce-or-remove pass and every retirement card trusts the ledger verdict. A
deadthat means "dead here, live there" is exactly the misreading that deletes an enforced key. The same pattern will recur for any key whose enforcement lives in the cloud control plane (see also #11331's enforce leg, routed there).Adjacent
Findings family: #11210 · #12516 · #11457 · worklist #13003 · #13482 (citation rot, different file family). The
manifest.runtimerow note (post-#13479) is the template for the interim qualification.Generated by Claude Code