Skip to content

[PM seat] domain:engine-core — 🟢 os-zhuang (fable wall CLEARED, in flight 0) #6019

Description

@claude

This post is the single authoritative registry for the domain:engine-core seat. Seat-post protocol (maintainer-approved 2026-08-06): index = label:pm:seat, entry point #4604.

Bounded body (six sections, #7583). Current state only, edited in place — ⛔ never appended to per event.

1. Scope

packages/objectql (including SchemaRegistry — #1825) / packages/core / packages/formula / plugin-pinyin-search.
⛔ Not this seat: packages/metadata*domain:metadata (#6367) · metadata acceptance surface ⇒ domain:spec (#6017) · /meta route + packages/restdomain:cli (#6024) · packages/drivers/driver-*domain:drivers (#6020) · content/docs/**domain:devx (#6023) · packages/services/**domain:services (#6021).
⚠️objectql/src/metadata-facade.ts IS this seat's despite the name. Assume a card is wider than its card text says — measured twice this shift: #8118's consumer half was entirely service-messaging with zero files in the plugin-webhooks its claim declared; #7378's guard in packages/core reached five other packages' test configs.
⚠️A lane boundary is not read off the card's title — routing follows the ruled landing site, and a card's thread outranks this post.

2. Current PM

🟢 os-zhuang, session session_01RDTnVvsgA6cUZ4xFVtPZRy — took the seat 2026-08-13 ~04:3xZ.

The handover condition is spent: the Fable 5 quota was verified live and the five-card wall is CLEARED. ⛔ Nothing was reclassified to get there — every card ran at the tier it always required.

⚠️The predecessor and I share the login os-zhuang. The assignee field cannot say which session holds a claim — the session ID in the claim comment is the only discriminator.

3. Ledger — shift opened 2026-08-13 ~04:3xZ · in flight 0 · enqueued 0

Landed this shift: 5 — each verified by reading the merged tree's CONTENT, ⛔ never the commit message (which only proves a merge happened).

cardPRwhat was checked in the merged tree
#8215#8319if (name === SystemFieldName.ID) return false; at rule-validator.ts:1447 + the doc clause
#7501#8322max_scale in record-validator.ts, errors.zod.ts, and the hand-written error-catalog.mdx (the patch round)
#7589#8327INVALID_FIELD live in engine.ts; the dotted teaching example gone from types.mdx
#8118 (security)#8348internal: true on headers_json; resolveInternalField at engine.ts:5213with its INVALID_FIELD guard at :5228
#7378 (half)#8349shared guard present; line 95 is import type; all 5 vitest configs carry spec/shared
statecards
⛔ Open, blocked#7378Blocked-by: #8350. Implementation half landed; the contract's reference double + spec text remain. ⚠️ Its Blocked-by: token is in a comment, not the body — declared, not hidden: the API returns the body HTML-escaped and rewriting it would double-escape the card. A body-only grep will miss it
Transferred out#8350domain:spec (#6017). ⭐ Urgency is not the lagging table: metadata-service.ts TSDoc says "(c) PARKED — do not implement" about behaviour now in main
Now dispatchable#7519 — its stated dependency (cell 3) is satisfied: the facade's {name, content} boxing and silent reconcile are gone. ⛔ Never batched with other metadata-facade.ts work
Decision box (maintainer's)#5320#8070 is pm:blocked on it and is the same decision; ⛔ do not answer separately
⚠️ Owed: unblock scan#7737 · #5571pm:blocked, ⛔ NOT fable-walled, absent from the handover's first-batch list. Never scanned this shift
Filed this shift, unassigned + ungraded (triage's)#8321 (authoring-time refusal of malformed scale) · #8329 (v17 release notes prescribe a now-refused dotted fields remedy — release-owned) · #8351 (check:test-source-alias blind spot) · #8352 (check:i18n structurally underivable)
⚠️ Anchors — pm:dispatched, NO dev#7620 · #4953. Both used Part of #N. ⛔ Never reclaimed, ⛔ not relabelled
pm:queue remainder#7823 — ⛔ assigned to huangyiirene, PR #7996 open; that seat's label to fix
Findings held#7880 · #7934 · #7877 · #7951 · #7988 · #8032 · #8047 · #8070 · #8116 · #8194 · #8210 · #7264 · #6896
On hold#5930 · #5180 · #3166 · #3146 (status:parked)

Cross-seat declarations open to merge: #6367 (metadata), #6020 (drivers — ⚠️ includes my explicit judgement that a one-line test-config repair falls outside the 2026-08-05 driver-memory investment freeze; that seat can overrule), #6024 (cli), #6021 (services), #6023 (devx).

4. Hot-file serial queue

⚠️A region clearance comes from the other card's ACTUAL CHANGED-LINE RANGES — read its diff when a PR exists, declare UNKNOWN when one does not. ⛔ Never from the address of the symbol the other card is named for.

Measured failure (prior shift):#7933 cleared against #7989 as "158 lines apart"; the merge conflicted in that exact block, because #7989retired a gate rather than adding one. ⛔ A card that REMOVES something has a range nobody can infer from the name of what it added.

This shift the rule PREVENTED rather than explained a collision: #8118 was held off the batch because #8327deletesengine.ts's head-only filter. Distance would have cleared it. ⚠️And the hold outlived its label#8118 read pm:blocked (quota) for ~50 min after the quota lifted, while the real constraint was the file serial. A "blocked" label that does not say what it is blocked ON invites the next PM to unblock it on an expired reason.

⚠️Line numbers rot within hours#7589's projection filter moved :6996~:7161 inside a day. Locate by symbol, always.

Held right now: nothing — the lane is idle.metadata-facade.ts is free (⚠️#7519 next).

5. Standing commitments

  1. Read each gate job's OWN conclusion before any ready-flip or enqueue. ⛔ Never an aggregate; ⚠️get_status is a false green; ⚠️filter still queued means the shards are not scheduled. ⭐ A patch commit RESETS the whole farm — the previous head's green does not carry forward (four patch rounds this shift each re-ran 24–26 jobs from zero).
  2. ⛔ Baselines may only shrink. Never raise a ledger entry, never run --lower.
  3. ⚠️list_issues does not return assignees, and its labels filter is OR, not AND.
  4. An inherited ledger's state claims expire faster than its lessons. Re-read every card you act on — [security] sys_http_delivery.headers_json still stores webhook credentials in cleartext — and every services-lane shape for fixing it is structurally wrong #8118's inherited "blocked on quota" was true and had been superseded by a file collision nobody had looked for.
  5. A premise is only as good as the surface it was measured over — demand that surface be named in the brief.
  6. Page long threads to the END. ⭐ The flake discriminator is two-part: zero failing assertions tells you HOW a job died, not WHETHER your diff caused it.fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349's red was 16 files dead at load with 29 tests passing — and the stack named the new module.
  7. A suite resolving built dist measures nothing after a src-only change.⚠️ Unbuilt-dist reds are prerequisites, not findings — and ⛔ not passes either. Hit by every dev this shift; all named it correctly.
  8. ADR- and skills-amending PRs are MAINTAINER-MERGED ONLY (PD feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14). ⚠️The fork keys on docs/adr/**, NOT on a bare docs/ prefixfix(objectql)!: engine.find/findOne refuse a dotted projection instead of widening to every field (#7589) #8327 and fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349 both carried docs/protocol-upgrade-guide.md and correctly did not fork.
  9. Archiving is part of confirming a merge — can 404 on an ownership boundary. mode:subagent cards have no container.
  10. Declare cross-seat and proceed, with a stated deadline.A declaration that has MERGED is spent — check the PR's state (feat(spec): comparand-type door — the accepted literal comparand set, enforced once at the shared compile face for all five drivers (#7872) #8234, fix(metadata-protocol): the /meta list serves one row per name after a runtime PUT #8332). ⭐ Offer the separable commit when the work splits cleanly; returned four times this shift.
  11. When a hold or claim turns out wrong, withdraw it in the same public place it was posted.
  12. The fable clause follows the CHANGE, not the lane label. ⛔ No downward discretion. ⭐ Probe the quota with a read-only agent, never with a claim.Both directions are now measured: the predecessor's five blocks were correct and cost nothing because each was pre-staged; when the quota returned the whole wall moved in one shift.
  13. A grade is triage's to produce, and that does not get to be selective.
  14. A dev that reads the CARD over the DISPATCH is doing its job. This shift: A number field's declared scale is never enforced — values with more decimals are accepted and stored verbatim (min/max on the same field are enforced) #7501's dev falsified my "0 driver hits" with a measured 11; finding: SqlDriver's #3821 recovery ladder widens an unresolvable projection to every field #7589's dev tested my seam-distinctness assumption against real hunks and extended the caller analysis past my brief; [security] sys_http_delivery.headers_json still stores webhook credentials in cleartext — and every services-lane shape for fixing it is structurally wrong #8118's dev added the accessor's internal:true-only guard nobody asked for, without which a privileged dereference is a generic read-protection bypass over ADR-0100's masked password.
  15. Death-cause, not death-count, decides the response.API 529 ⇒ revive in place. Quota ⇒ ⛔ no retry loop, pm:blocked, named in every report.
  16. "Push early" has TWO reasons — surviving a kill, and: ⛔ never reverse-verify before committing (with no commit, both checkout forms resolve to the same tree and the restore destroys the fix). ⭐ The branch's contents then decide the label: work pushed ⇒ pm:blocked + assignee kept ([security] sys_http_delivery.headers_json still stores webhook credentials in cleartext — and every services-lane shape for fixing it is structurally wrong #8118 — and it saved four commits); bare pointer ⇒ claim released (MetadataFacade answers three registerget round-trip cases differently from every other shipped IMetadataService #7378). The label follows the evidence on the branch, ⛔ not a uniform policy.
  17. Verify a docs-drift advisory instead of pattern-matching "advisory only". It paid for itself THREE times this shift — advisories of 109 / 109 / 16 pages, exactly one real hit each: error-catalog.mdx's bounded-ranges row missing the code the PR added; types.mdxteaching the false populate premise the same PR was deleting from code; webhooks.mdx advertising a column the PR made internal, directly under a sentence the PR was making true. ⭐ The method is not reading 109 pages — it is reading the ONE page whose SUBJECT matches the change. ⭐ And a negative is a real result: fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349's 29-page advisory had none.
  18. A card whose closure condition is "when the sub-cards land" has no reader.
  19. "Drop the as any so the compiler catches it" is FALSE in packages whose tsconfig excludes test files ([finding] query-options/no-any-erasure's test surface promises a guard tsc cannot deliver — 20 packages exclude **/*.test.ts from their tsconfig #8210).
  20. A dev's local gate exit code is not a fact about CI — third instance this shift (check:objectui-pin-fresh red locally, Console Pin Freshnesssuccess). ⛔ Neither direction transfers.
  21. A merge-queue red is a BATCH verdict; a PR-run red is not. Discriminate by mechanism ("can my diff physically reach this code path?"), never topical similarity.
  22. check:type-check-debt leaves a live tripwire in a tracked dir — ⛔ dispatches forbid git add -A; acceptance reads the PR's file list.
  23. A pin that derives its expectation from the code under test cannot detect a change in it. ⭐ Correct rewrite shape (fix(objectql): a preserveAudit by-id update no longer hands the primary key to the driver #8319): literals for load-bearing facts, the composer retained only for the wording contract.
  24. A gate that REFUSES TO RUN is not a gate that passed — in either direction.
  25. Never write an identifier you did not receive.
  26. A shared login makes the assignee field mute. Compare session IDs in claim comments.
  27. The instrument failed FOUR times this shift, always the same way: a DERIVED ref that did not mean what I assumed.ls-remote run outside the repo ("no branches" — false), the same call with stderr sent to /dev/null hiding the error that would have caught it, origin/main...FETCH_HEAD after a later fetch overwrote FETCH_HEAD (empty diff — false), merge-base returning a base 734 commits back (garbage). ⛔ Every zero-hit and every surprising diff needs a POSITIVE CONTROL before it is a measurement — a known-present neighbour, or an expected count. ⛔ Never suppress stderr on a verification command. Not one of the four was caught by reading the output; all four by the control. ⭐ Same discipline caught a false alarm in the other direction: via populate grepped 1 hit where the ruling demanded 0, and reading it showed the new docblock describing the removal in past tense — a grep cannot tell a claim from a description of a claim, and acting on the count would have opened a rework round against correct code.
  28. NEW — "ran a downstream consumer" is not "covered the consumer face."fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349's dev swept @objectstack/runtime and stopped; I accepted that in review. Three CI jobs then found two consumer packages dead at load. For a change landing in the lowest common dependency, the consumer face is the whole repo — demand the class be counted, not a sample run.
  29. NEW — the job NAME is not the failure.fix(service-messaging,objectql): stop serving sys_http_delivery.headers_json on the generic read path — internal: true + a batch privileged accessor (#8118) #8348's red arrived as TypeScript Type Check and was actually check:i18n. ⛔ Open the log before reasoning about a cause; a plausible story built on the job name sends you hunting for a defect that does not exist.
  30. NEW — convention-triggered gates are the PM's to NAME, because path derivation structurally cannot.check:i18n fires on what the change IS (an object-definition edit restaling bundles); check-i18n-bundles.mjs discovers its population at runtime, so its source carries no path literal for dispatch-gates.mjs to match (dispatch-gates.mjs cannot derive check:i18n from an object-definition edit — the checker discovers its population at runtime, so no path literal exists to match #8352). ⭐ Two gates this shift were green while shipping the very defect class they are named for (check:test-source-alias resolves only intra-package specifiers, so an aliased-to-src dependency's OWN subpath imports can hit the prefix-swallow ENOTDIR its rule 5 exists to refuse — measured green while two packages shipped red #8351, dispatch-gates.mjs cannot derive check:i18n from an object-definition edit — the checker discovers its population at runtime, so no path literal exists to match #8352) — a passing gate is not evidence its class is clean.
  31. NEW — label a PM lean as a lean, and mean it. On fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349 I leaned "fix the import in core, not five consumers." The route did not exist (neither symbol is exported from the spec root; adding one is fenced spec surface). The dev measured, said so, and produced a better answer than either of us started with — it halved the runtime demand and argued the remainder was forbidden to inline by row 2's own ruling. ⛔ A lean stated as a ruling would have bought the worse fix.

6. Notes

⚠️Raw GitHub HTTP does not work in this fleet (403; tokens empty; no gh). scripts/pm/check-half-states.mjs's 401 is permanent — half-state discipline is manual. ⭐ Subagents CAN reach the GitHub API.

⚠️A get_session / archive_session 404 is an OWNERSHIP boundary, not a death certificate.

⚠️Measured dev baseline, this lane: dispatch → pushed PR = ~40 min (M, one file + doc clause), ~57 min (M, cross-package + a spec catalog member), ~70 min (M–L, engine seam, 8 enumerated faces), ~85 min (L, resume + 89-commit merge + full re-verification). Patch rounds ~8–25 min, the longer ones being real investigations. ⛔ 45 min is a probe threshold, never a death call. ⭐ For mode:subagent devs, no completion notification is positive evidence of liveness — it outranks "no branch yet".

⚠️priority:p2 is a real repo label with no named reader in the pm state machine. ⛔ Preserved verbatim in label writes.

Merge-queue reading: membership = the enqueued / added_to_merge_queueevent; the auto-merge receipt's empty fields carry zero information (#7492) — 5 more empty receipts this shift, all 5 enqueues real. ⚠️ Queue membership does not survive a draft conversion, and notices can arrive out of order.

Flakes: Corepack pnpm --version death ~13s ⇒ transient. verify signIn failed: 500 ⇒ transient. Check Documentation Links red at lychee-setup with curl exit 22 and both lychee steps skipped ⇒ the checker never ran; plain re-run. ⛔ A red insideRun Lychee is a different verdict.

Gate-invocation corrections: check:doc-formula-expressions has no root script (exits 254) — use pnpm --filter @objectstack/lint run …. check:i18n needs a built CLI. check:type-check-debt --re-measure needs a built closure and refuses without one. ⭐ The PM's point-named list is a LEAD, not a spec — devs re-derived against real diffs this shift and found 16, 4, 3 further families on three cards. Reporting the additions is part of the job.

Patrol cadence: ≤45 min with anything unlanded, 60–70 on standby. ⏱ ARMED: trig_01BJm7UBwi8f4zMujGAj9BDh, fires 2026-08-13T08:59:00Z — copied verbatim from the tool result (§5.25).

Metadata

Metadata

Assignees

Labels

pm:seatPM seat registry issue - single-writer body, index = this label

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions