lane consolidation: engine-core+metadata+drivers → domain:engine; identity folds into domain:services — table first, rename trick, 44-card migration #9854
Description
Activity
Correction to the "seat work after the PR merges" section, from the maintainer (2026-08-19, PM chat, verbatim): 「所有项目经理现在没有 用 Routine,只有分诊是 Routine,都是我收工安排的。」
Item 4's "create ONE
servicesseat Routine in the Routines UI" is therefore withdrawn — execution seats are maintainer-arranged chat sessions, not Routines, and this card must not manufacture a new obligation. The operative form under manual staffing: the consolidated lanes are simply the names the maintainer invokes —/pm-dispatch engineand/pm-dispatch services— whenever they next staff those lanes; nothing to create anywhere. Everything else in the card (table-first sequencing, rename trick, 44-card migration, seat-post consolidation) stands unchanged. The consolidation's payoff is restated accordingly: fewer lanes = fewer sessions the maintainer has to hand-arrange per shift, which was the stated pain.
Generated by Claude Code
Claim: PM loop round 4 — family dispatch (lead card), maintainer-ordered fold (2026-08-19 verbatim: 「9855 9858 都合并了,开始折叠派发」; fold authority: 「SKILL.md 串行链 为什么不能合并成一个卡伐」)
Session:session_01AeA3nU1B5Q2pgxqxgUrexd
Branch:claude/issue-9854-skill-chain-fold(shared by all five folded members)
Worktree:objectstack-issue-9854
Domain:domain:skills
File surface:.claude/skills/pm-dispatch/SKILL.md+references/seat-post-protocol.md+ newreferences/lanes/*.md(6 files) +scripts/pm/check-skill-line-ratchet.mjs(CEILINGS entries for the new files) (stop on breach; explain in the report)
Container & model: L (five ruled cards, one coherent SKILL.md pass),mode:subagent,model: claude-fable-5— mandatory per this dispatch'sdispatch-gates.mjs --tierderivation (clause ①,.claude/skills/pm-dispatch/**)
Clause-②: no
Serial constraints cleared: SKILL.md settled — #9855 merged (5af0685d6) and #9858 merged (b1e7842e2) on fetchedorigin/main, both verified this round; no open PR touches the pm-dispatch tree (#9862 is workflows + check-half-states, disjoint). Folded members, each carrying its own claim comment naming THIS branch: #9776, #9852, #9663, #9871. One PR, per-card commits, multi-Fixesbody. Fold admission per the five gates on #9663: all members ruled ✓ (four maintainer-verbatim, one seat-graded), one file/region ✓, one worktree ✓, per-card commits = per-member verifiability ✓, exclusion list = none look-alike excluded (nothing else queued touches SKILL.md).
Generated by Claude Code
File-surface supplement to the lead claim (same-round declaration, dev session
session_01AeA3nU1B5Q2pgxqxgUrexd): commit 1 also touchesscripts/pm/ensure-pm-labels.sh. Evidence pinning the fix: the script's own header mandates "Domain lanes — the roster lives in SKILL.md's domain table; keep both in sync BY PR whenever a lane is added or retired", and SKILL.md's 一次性建标签 line makes the script header the authority on retired-lane absence. Leaving the loop creating four retired lanes while the same PR retires them in the table would violate both. Bounded to: the lane roster loop + the retired-lanes header comment. Also measured for the seat-work rename: no leftoverdomain:enginelabel object exists on objectstack (get_label 404), so thedomain:engine-core→domain:enginerename path is clear.
Generated by Claude Code
Generated by Claude Code
- added a commit that references this issue
on Aug 19, 2026 { "issue": 9854, "status": "done", "branch": "claude/issue-9854-skill-chain-fold", "pr": "https://github.com/objectstack-ai/objectstack/pull/9899", "premise_still_valid": true, "members": [ { "issue": 9854, "commit": "3f64a39e9", "status": "done", "premise_still_valid": true, "delivers": "table merge engine-core+metadata+drivers into domain:engine; identity folds into domain:services; four labels marked retired in the table; stale-name sweep (one hit fixed, os-dev.md zero hits); ensure-pm-labels.sh roster synced per its own same-PR mandate" }, { "issue": 9871, "commit": "c7683ca6b", "status": "done", "premise_still_valid": true, "delivers": "six lane files under references/lanes/ seeded from the nine live seat posts; seat-post template 6 to 4 sections in SKILL.md + seat-post-protocol.md; spec intra-seat reference relocated to lanes/spec.md; CEILINGS entries at landed counts + self-test case; live seat-post bodies untouched" }, { "issue": 9852, "commit": "22ba7c211", "status": "done", "premise_still_valid": true, "delivers": "request-card protocol on 跨座位转移: any cross-seat ask is a card in the target queue (provenance + one-line executable criterion); wait flips pm:blocked + Blocked-by: same stroke; knocks demoted to accelerators; seam-card routing for unreachable repos" }, { "issue": 9776, "commit": "684466cd0", "status": "done", "premise_still_valid": true, "delivers": "pm:blocked row extension: done-but-unlandable uses Blocked-by: at the gate card + machine-readable Unlock-action re-check-PR line; re-queue premise check treats a finished open PR as landing work; parked PR names the gate card in its body; no new label" }, { "issue": 9663, "commit": "7371c47c5", "status": "done", "premise_still_valid": true, "delivers": "批次独立性 absorbs family dispatch: five admission gates (gate 3 ruled-only and gate 5 exclusion list load-bearing); fold-or-serial mandatory question with the maintainer verbatim; folded-claim conventions written into the claim protocol from this dispatch's own record" } ], "summary": "All five members delivered on one branch, per-card commits in dispatch order, one draft PR with five Fixes lines. SKILL.md lands at exactly 682/682: the five additions were funded by the table merge (5 rows to 2), the spec-reference relocation, the fixture-triage rule relocation to lanes/spec.md, and two pointer-collapses against platform-readings.md (verified against its actual headings) — genuine dedup only, no re-wrap of existing content. Governed surface: PR stays draft for the maintainer.", "tests": "All at head 7371c47c5, exit codes captured before any pipe. dispatch-gates.mjs (no paths) derived 9 families; all green: check:pm-skill-ratchet exit 0 ('SKILL.md is 682 lines (ceiling 682; headroom 0)', six lane files at headroom 0, self-test 14 cases); check:pm-skill-id-lint exit 0 ('15 file(s) clean' — lane files inside the scan set); check:doc-authoring exit 0 ('377 files clean'); check:skill-frame-sync exit 0 ('binding sentence present in all 4'); check:pm-governed-prose exit 0 ('2 instruction surface(s) name all 5 registered governed surfaces'); check:pm-governed-merges exit 0 (77 assertions); check:cross-package-test-inputs exit 0 ('OK: 12 package(s)'); lint check:doc-formula-expressions exit 0 ('22 record-scoped formula example(s) judged clean') after building the lint dependency closure (first run was the unbuilt-dist prerequisite, not a finding); check:nul-bytes exit 0 ('scanned 6288 text file(s), no raw ASCII control bytes').", "line_budget": { ".claude/skills/pm-dispatch/SKILL.md": "682 -> 682 (ceiling 682, headroom 0)", ".claude/skills/pm-dispatch/references/seat-post-protocol.md": "101 -> 101 (ceiling 101)", ".claude/skills/pm-dispatch/references/lanes/engine.md": "new -> 41 (ceiling 41)", ".claude/skills/pm-dispatch/references/lanes/services.md": "new -> 31 (ceiling 31)", ".claude/skills/pm-dispatch/references/lanes/cli.md": "new -> 37 (ceiling 37)", ".claude/skills/pm-dispatch/references/lanes/devx.md": "new -> 38 (ceiling 38)", ".claude/skills/pm-dispatch/references/lanes/skills.md": "new -> 36 (ceiling 36)", ".claude/skills/pm-dispatch/references/lanes/spec.md": "new -> 44 (ceiling 44)" }, "deviations": [ "scripts/pm/ensure-pm-labels.sh added to the declared file surface (same-round supplement comment on this card): its own header mandates same-PR roster sync on lane retirement; bounded to the lane loop + retired-lanes comment. It also records that domain:engine re-enters circulation after its own earlier retirement — and get_label confirms no leftover domain:engine label object, so the seat-work rename path is clear.", "scripts/pm/check-half-states.mjs self-tests use the literal domain:engine-core as an arbitrary fixture label; judged inert (asserts nothing about lane vocabulary), left untouched.", "One migrated-prose conflict resolved in SKILL.md's favor and filed as a finding (see out_of_scope_findings): devx seat post flips governed ADR PRs ready-for-review; SKILL.md's ACCEPT fork forbids the flip. lanes/devx.md follows SKILL.md.", "main moved 7 commits after branch creation; measured zero overlap with .claude/ and scripts/pm/ (empty diff on those paths) — no merge taken.", "No changeset: diff is .claude/** + scripts/pm/** only; skip-changeset applied via read-modify-write after the label bot settled and verified by read-back (documentation, size/m, skip-changeset)." ], "files_changed": [ ".claude/skills/pm-dispatch/SKILL.md", ".claude/skills/pm-dispatch/references/seat-post-protocol.md", ".claude/skills/pm-dispatch/references/lanes/engine.md", ".claude/skills/pm-dispatch/references/lanes/services.md", ".claude/skills/pm-dispatch/references/lanes/cli.md", ".claude/skills/pm-dispatch/references/lanes/devx.md", ".claude/skills/pm-dispatch/references/lanes/skills.md", ".claude/skills/pm-dispatch/references/lanes/spec.md", "scripts/pm/check-skill-line-ratchet.mjs", "scripts/pm/ensure-pm-labels.sh" ], "open_questions": [], "out_of_scope_findings": ["filed as #9900: SKILL.md's governed-PR fork (never flip ready) contradicts the devx seat post's standing ready-for-review practice on parked ADR PRs — needs a ruling on which way the carve-out goes"] }
Generated by Claude Code
Generated by Claude Code
ACCEPT — all five members, reviewed per commit against GitHub. PR: #9899 (draft, five
Fixeslines, per-commit map in body)- lane consolidation: engine-core+metadata+drivers → domain:engine; identity folds into domain:services — table first, rename trick, 44-card migration #9854 (3f64a39): table rows merged with package families verbatim, freeze note riding its packages, retire-from-circulation-keep-objects semantics stated in-table;
ensure-pm-labels.shroster sync accepted as a justified surface supplement (its own header mandates same-PR sync — the dev quoted it); stale-name sweep result verified (one hit fixed inside the relocated spec reference, os-dev.md clean). - per-lane PM job descriptions move from seat-post prose into versioned skill references — seat posts shrink to pure state #9871 (c7683ca): six lane files spot-checked (
spec.md,skills.mdread in full by this seat) — high-fidelity migration; both relocation payments verified surviving: the spec intra-seat reference and the fixture-triage rule both live inlanes/spec.md, and the fixture rule's new home is more correct than its old one (it was always spec-lane-specific). Clause ② 's judging reference now points atlanes/spec.md— single source held. Template 6→4 landed in both SKILL.md and seat-post-protocol; live seat posts untouched as required. - cross-seat requests parked as prose (seat-post knocks, ruling comments) leave the waiting card lying in pm:queue — requests must be cards, waits must be pm:blocked at them #9852 (22ba7c2) / finding: no state expresses "card is done, its PR is blocked by a gate defect that is not this card's" #9776 (684466c) / [finding] pm-dispatch cannot express "one dev, N same-shape cards, one PR" — the batch-independence rule reads as forbidding it, so seats pay a full dev cycle per family member #9663 (7371c47): all three clauses land faithful to their adjudicated directions, with the maintainer verbatims in place; [finding] pm-dispatch cannot express "one dev, N same-shape cards, one PR" — the batch-independence rule reads as forbidding it, so seats pay a full dev cycle per family member #9663 additionally encodes this dispatch's own folded-claim conventions and the fold-or-serial mandatory question.
- Ratchet: SKILL.md exactly 682/682 with every payment audited (pointer-collapses checked against platform-readings' actual headings); six new CEILINGS entries + self-test case.
- Gates: 9 derived families green with quoted verdicts at head
7371c47; id-lint auto-covers the new lane files (15 files clean). - Out-of-scope finding finding: SKILL.md's governed-PR fork says "never flip ready", while the devx seat post's standing practice flips governed ADR PRs ready-for-review so the maintainer's merge button works #9900 verified filed; graded separately (decision box — it touches the merge-is-review protection).
- Governed surface ⇒ terminal three-step: review recorded here; the PR stays draft, visibly awaiting the maintainer's merge — one merge lands the whole chain; the round report lists it under "awaiting a human merge". On merge, this seat executes the recorded seat-work package: label rename + 44-card migration + seat-post consolidation and 4-section shrink +
ensure-pm-labels.shrerun.
Generated by Claude Code
- lane consolidation: engine-core+metadata+drivers → domain:engine; identity folds into domain:services — table first, rename trick, 44-card migration #9854 (3f64a39): table rows merged with package families verbatim, freeze note riding its packages, retire-from-circulation-keep-objects semantics stated in-table;
Seat-work package: EXECUTED (2026-08-19 ~07:1xZ, skills seat, session
session_01AeA3nU1B5Q2pgxqxgUrexd)PR #9899 merged by the maintainer → all recorded seat work is done:
- Label migration, 55 open cards, per-card read-modify-write with bulk read-back:
domain:identity→domain:services(25 cards, read back 0 residue);domain:engine-core(11) +domain:metadata(11, seat post excluded) +domain:drivers(8) →domain:engine(read back: exactly 30 cards on the new label; all three retired labels at 0 open, except [PM seat] domain:engine — ⏳ vacant #6367 — deliberate, see 3). Branches, claims, and assignees untouched throughout. - Deviation from the recorded plan, in the table's favor: the rename trick (
engine-core→engine) was dropped — it contradicted the landed table's letter (「三标签退役…对象保留」: a renamed object does not remain under its retired name) and would have made engine-core's archive semantics differ from the other three retired lanes. All four retired labels now retire identically: out of circulation, objects intact on closed cards.domain:enginewas auto-created by the first card write (its earlier 2026-08-1x retirement left no leftover object, as the fold PR verified). Cost: 11 extra writes. - Seat posts: vacant
identity([PM seat] domain:identity — 🔚 retired 2026-08-19, merged into domain:services (#6021) #6022) +services([PM seat] domain:services — 🟢 os-warren · session_01CeRCvvvjxbxu2iYJAc5Cce #6021) consolidated → [PM seat] domain:services — 🟢 os-warren · session_01CeRCvvvjxbxu2iYJAc5Cce #6021 is the four-sectiondomain:servicespost pointing atlanes/services.md; [PM seat] domain:identity — 🔚 retired 2026-08-19, merged into domain:services (#6021) #6022 closed with a moved-into audit comment. The engine-side three posts are held by an active session, so per the just-landed request-card protocol the consolidation ask is a card in the engine queue (request: engine seat — consolidate the three legacy seat posts into one domain:engine post (post-merge seat work) #9912) with a one-line executable close criterion — ⛔ not a seat-post knock; [PM seat] domain:engine — ⏳ vacant #6367's label swap is deliberately bundled into that step. ensure-pm-labels.shroster already synced in the PR itself; the script needsgh(absent here) — its next maintainer-side run is optional hygiene, not owed.
Lane consolidation is now fully live: table + tooling on
main, 55 cards migrated, one seat post per merged lane (engine side pending its sitting PM via #9912)./pm-dispatch engineand/pm-dispatch servicesare the invocation names.
Generated by Claude Code
- Label migration, 55 open cards, per-card read-modify-write with bulk read-back:
- added a commit that references this issue
on Aug 23, 2026 - added a commit that references this issue
on Sep 28, 2026
Maintainer ruling (2026-08-19, PM chat, verbatim): 「engine-core + metadata + drivers -> engine, identity + services → services 怎么样?」 — proposed by the maintainer over the skills seat's measured lane-distribution report (13 seats → 10; the three engine-side lanes total ~4 active cards and are already de-facto run by one session; both identity and services seats are vacant with ~16 active cards combined). This card implements it. Lane-label merge (not a multi-lane seat): the 一座位一车道 bijection survives unchanged.
Sequencing constraint (binding)
The anchoring table lands BEFORE any new label enters circulation — a label in circulation but not in the table is an ownerless lane. So: this card's PR (table + tooling text) merges first; the label operations follow as seat work.
Scope of the PR (this card's dispatch)
.claude/skills/pm-dispatch/SKILL.mddomain-lane table (锚定规则):domain:engine-core/domain:metadata/domain:driversrows into onedomain:enginerow carrying all three package families verbatim; keep the maintainer's 2026-08-05 investment-freeze note on thedriver-memory/driver-mongodbfamily (the freeze rides the packages, not the lane).domain:identity's four packages (plugin-auth,plugin-security,plugin-sharing,plugin-audit) into thedomain:servicesrow.grepforengine-core|domain:metadata|domain:drivers|domain:identityacross.claude/skills/pm-dispatch/**,.claude/agents/os-dev.md) and update or point them; report what was found.Seat work after the PR merges (NOT the dev's; recorded here for the executing seat)
domain:engine-core→domain:engine(GitHub rename carries all open+closed cards at zero per-card cost).domain:metadata(12 open) anddomain:drivers(8 open) →domain:engine;domain:identity(24 open) →domain:services. Closed cards keep their historical labels.domain:enginepost (edit history is the archive; the holder session is asked via a queue card per the request-card protocol, not a seat-post knock); the two vacant identity/services posts collapse into onedomain:servicespost.servicesseat Routine in the Routines UI; merge this card's PR when it reaches the chain head.Counts measured 2026-08-19 ~05:3xZ (open cards): engine-core 11 · metadata 12 · drivers 8 · identity 24 · services 14.
Graded at filing by the skills seat (own-lane exception):
pm:queue, S/M..claude/skills/pm-dispatch/**⇒claude-fable-5mandatory; governed ⇒ draft PR, maintainer merge. Serial: SKILL.md hot-file chain — maintainer-direct channel priority: next after the in-flight hold-discharge card lands, ahead of the remaining chain queue.