Repository navigation
Description
epic:#31527#1 · os-project-manager · session_01FEkQ5mLd7pR2PHjsPwiGkz
Filing gate: ④ coordination node: child E7 of the epic #31527 (parent and per-layer children), as ADR-0150 (docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md, merged in #31586 at 5d1382a)'s execution plan lists it. Hand-over card: filed undispatched as the epic seat signs off (maintainer 2026-11-08T16:34Z 「专题卡当前任务处理完,合并后就下班」). ⛔ Not a claim.
Ruling-ref: per-type table A (6723462584); epic A 「立专题」 (6723499113); division of labour A 「留核心,其余交车道」 (6723571682); ADR-0150 accepted by merge (#31586, 2026-11-08T21:16Z).
Business reason: inherited from the parent #31527. Behavioural metadata is addressed by (package, name), so two installed packages can each ship an item of the same name and every reader answers the right one, or refuses with the candidates, instead of silently taking the first match.
Reader: the next domain:server seat picks it from the queue (pm-dispatch selection) and accepts its PR against the red lines below.
Dedupe (open AND closed): jobKeyFor (2; top hits #31527(open) #21602(closed), none on point: they are this epic, its parent #30806, or unrelated cards).
class: d · type: Feature
Grade: p1, inherited from the parent (self-graded under 「定级你可以自己决定」).
Blocked-by: #31575
维护者速读
定时任务的键带上软件包坐标,旧的裸键继续可读。
What to build
jobKeyFor reads the package coordinate; the first holder keeps the bare key and a second keeps its APPID:jobName, as today.
Surface
- Expected file surface: runtime
app-artifact-handlers.ts, service-job. - Clause-②: no.
- Narrowing: no: the first holder keeps the bare key and a second keeps its
APPID:jobName, asjobKeyForgives them today.
Acceptance — the epic's three red lines (every child shares them)
- Resolution never loosens. No first-registered fallback, no environment-wide guess for a caller with a package, no silent pick.
- Ambiguity is reported, never guessed. Every refusal and every migration report names every candidate.
- Independently releasable (red line 3). The PR proves it with ADR-0150's four readings: (a) the phase-1 one-holder tests stay green; (b) bare-name behaviour (URLs, MCP, SDK) is unchanged for every name with one holder, except this card's declared narrowing; (c) any migration is re-runnable and never guesses; (d) its
Clause-②:declaration and, where it changes the protocol, its ADR-0087 migration entry. - The epic seat is off duty after hand-over: the accepting lane seat checks these lines itself, and a narrowing beyond the declared one goes to the maintainer before landing.
Parent: #31527.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: confirmed ·
domain:server· p1 ·pm:blocked· 2026-11-08T21:58Z⛔ Not a claim.
epic:#31527#1is online, and the maintainer ruled 「留核心,其余交车道」. The children live in lane queues withoutpm:epic, which matches [Decision] Epic-driven delivery as the next working mode: one epic = parent + epic seat + milestone table; children as sub-issues withpm:epic+Blocked-by:; rolling split; mandatory hand-over when an epic seat leaves; a cap on concurrent epics #31502 A′.domain:server, by package ([Decision] Keepdomain:devxanddomain:serveras separate lanes, or merge them? Measured load and boundary friction, 2026-11-08 #31424 rule 1).Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
epic:#31527#1 · os-steve · session_01ADHkmP7o3uDTti21wLTfPf
Unblocked 2026-11-08T23:02Z:
Blocked-by: #31575is closed. R merged in #31637 as 0ebb080 (resolvePackageScopedName,packageResolutionClosureand the three read-onlySchemaRegistrypackage-scoped methods in objectql;packageDependencyClosurein metadata-protocol).pm:blocked→pm:queuein this stroke. Read the resolver through those exports only, and never re-implement the rule. The epic seat reviews this card's PR against the three red lines before it lands.objectstack-fleet commentedon Nov 8, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Claim: PM loop round 1 · #31679 (E7, epic #31527) · 2026-11-08T23:09Z
Session:
session_01ADHkmQXLfvyB5R53VDm3Ka(seat); dev = card threadsession_01ADHkmNp8ARUNvemy119dY1Account:
os-steveBranch:
claude/project-thread-znr079Worktree: the card thread's checkout of
objectstack-ai/objectstackDomain:
domain:serverSeat:
domain:server#3File surface:
packages/runtime/src/app-artifact-handlers.ts(jobKeyForand its callers),packages/services/service-job/src/**, their tests,.changeset/31679-*.md(stop on breach; ⛔ nopackages/specedit, no second resolver: R's exports only)Container & model:
M,mode:thread,model: default tier; CONTRACT_REVIEW_TIER for the review owed before the queue (dispatch-gates --tier: a card that only NARROWS owes one contract-review-tier review, judged from the card content),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6728384417
Premise: holds (R #31637 merged as 0ebb080; the card's
Blocked-by: #31575closed, moved topm:queueby the epic seat in 6728384417; the dev confirms the resolver exports onmainin step 0)Narrowing: no — the card declares none: the first holder keeps the bare key and a second keeps
APPID:jobName, as today; the dev shows identical keys on base and head for the same inputsSerial constraints cleared: seat 4's E2 #31673 touches runtime
action-execution.ts, notapp-artifact-handlers.ts: disjoint. S3 #31684 follows E1, E5 and E7 on this seat.objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmNp8ARUNvemy119dY1
os-dev-report
{ "issue": 31679, "status": "done", "branch": "claude/project-thread-znr079", "pr": "https://github.com/objectstack-ai/objectstack/pull/31730", "session": "session_01ADHkmNp8ARUNvemy119dY1", "premise_still_valid": true, "summary": "jobKeyFor now takes the job's package coordinate {packageId, name} (ADR-0150 D2/D4). Before falling back to this run's scheduling order, it reads the job catalogue (DbJobAdapter.readArming, optional and adapter-local, already in service-job) for the coordinate's own PACKAGE_ID:NAME key, and keeps that key when it is active. The first holder keeps the bare key and a second its PACKAGE_ID:NAME, as before, and that now holds across a restart that rehydrates packages in another order. Before, the bare key and its run history moved to whichever package the boot scheduled first. A job stored under its bare key is scheduled under it again and fires (the card's pin). No resolver call site: E7 resolves no bare name to a package, because a job is scheduled by its own package. R's resolvePackageScopedName is not called and no second resolver is written. Head ffa24bd0. The PR has no assignee: os-dev forbids assignees on pr_create, and MCP writes are barred.", "tests": "Step 0 / Clause-② key table, the same scratch harness on base b126c130 and head fc99b124, 10 inputs: S1-S7 and S10 byte-identical; S8 (restart scheduling the second package first: base hands the bare key to the second package) and S9 (restart after the bare holder's uninstall: base moves the scoped holder to the bare key) differ, and head keeps the catalogue's key. Full table in the PR body. New describe 'ADR-0150 E7 ...' in app-artifact-handlers.jobs.test.ts, 6 cases; file total 41 passed on ffa24bd0. Ablation via ablation-replace.mjs (catalogued forced false = the first scheduler takes the bare key): anchor 1->0, blob 1fb1fd13059d->e0c1c52e8cc3; 3 failed | 38 passed; restored, blob == HEAD, git diff HEAD empty. Source-imported test, so no dist leg. On fc99b124: runtime test 563 files, 9045 passed / 19 skipped, VERDICT 0; runtime typecheck VERDICT 0; service-job test 11 files, 121 passed, VERDICT 0; service-job typecheck VERDICT 0. Forced test edit in ffa24bd0: a module-top import '@objectstack/metadata' that check:test-source-alias prescribes for the edited file.", "gates": "dispatch-gates --commands on final head ffa24bd0: 64 derived, 64 run, all exit 0. --ran reconciliation: 64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Round 1 on fc99b124: check:test-source-alias exit 1 (fixed in ffa24bd0); check-plugin-teardown-shape --self-test exit 3 (fixture 621a4876 fetched, then exit 0); check:dual-build-cjs-loads exit 3 (packages built, then exit 0). Lint: npx eslint --no-inline-config packages/runtime exit 0 (runtime and service-job have no lint script; service-job is not edited). CI check-runs: not awaited, in_progress at report time.", "dogfood_battery": "fc99b124 · VERDICT command-exit 0 (1855s under lock) · Test Files 440 passed | 3 skipped (443) · Tests 3652 passed | 41 skipped (3693) · no failures. Run because the delta names dogfood; the title has no ! and there is no (narrowing) arm.", "mcp_calls": "4 — mcp__github__issue_read x4 (get #31679, get_comments #31679 x2, get #31527); no write tool", "api_writes": "2 — fleet relay pr_create (objectstack-ai/objectstack#31730, 11041 bytes sent and stored, identical); this os-dev-report comment via post-stamped.mjs. Plus git push x2 (not REST).", "open_questions": [ { "question": "The claim says 'show identical keys on base and head for the same inputs'. 8 of 10 measured inputs are identical. S8 and S9 (restarts) differ, because base moves a key that the catalogue holds for one package to another package or name. Is keeping it within the card's no-narrowing declaration?", "options": [ "A: keep the catalogue read. It is what 'the old bare key and APPID:jobName keys stay readable for stored jobs' and ADR row D4 ('the bare key stays readable for the one holder that has it today') ask; nothing is refused, so it is no narrowing", "B: drop the catalogue read and ship a pure re-key (S8/S9 stay as on base); file the restart key move as its own card" ], "recommendation": "A, because without it the card's own pin (stored keys stay readable) holds only when the rehydrate order equals the install order, which the #21602 integration test arranges by choosing ids that sort that way." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed: two scheduleAppArtifactJobs calls for the same job name that interleave (both before either claimJobKey) can both take the bare key. This is pre-existing (base checks in-process synchronously, then awaits schedule). This change awaits the catalogue read BEFORE that check, so the window is no wider.", "carrier: S3 #31684 · noted: R14 (sys_job.name follows the aligned jobKeyFor key) can now rely on the key being stable across restarts." ], "files_changed": [ ".changeset/31679-job-key-package-coordinate.md (+12)", "packages/runtime/src/app-artifact-handlers.ts (+117 -31)", "packages/runtime/src/app-artifact-handlers.jobs.test.ts (+160)" ], "line_budget": "289 added, 31 deleted, 3 files (Effort M). Source: +117/-31; tests: +160; changeset: +12.", "deviations": [ "service-job (named in the card's file surface) is not edited: readArming already exists on DbJobAdapter, and the runtime reads it structurally, as trigger-schedule does.", "Suites ran on fc99b124. The final head ffa24bd0 adds only a module-top test import, re-run on the edited file (41 passed); the 64 gates ran on ffa24bd0.", "No subscription to PR activity and no CI wait, per the os-dev contract." ] }Stamped 2026-11-09T00:29Z.
objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Landed · #31679 (ADR-0150 E7) · 2026-11-09T01:18Z
f2abd476, from headffa24bd0(seat ACCEPT 6729641661, epic PASS 6729440308)completedbyFixes #31679State:
pm:dispatchedremoved in this stroke. S3 #31684 still waits on E1 #31672 and E5 #31677.feat(service-automation, plugin-approvals, plugin-email, trigger-sche…