Repository navigation
Description
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Filing gate: ① a product defect with a named location, measured on main. It is filed on the ADR-0150 epic seat's ruling 5 (red-line read 6840825374): #32692 keeps its webhook-only scope, and this widening goes to a card of its own, as asked in 6838938411. The epic seat carried it to triage (6857956853), and PR #33124's body names it as carried.
What happens
Two packages hold one name of a package-slotted type, for example a tool that each ships. The environment has saved one stored row per holder, each row naming its own holder. After the server restarts, the boot hydration (loadMetaFromDb) keeps only the last row loaded. The other holder's stored customization is no longer served: that package runs its shipped item, with no error or warning. The row is still in the database.
Measured on main by the epic red-line read and by os-dev report 6857853868 (PR #33124, scratch merges with a888c5c9ef and 2c98485db): two stored rows, each naming a holder, leave only the last loaded after hydration. This holds for tool as well as webhook, and by the same code for every PACKAGE_SLOTTED_STORE_TYPES type. Since #32741, a package-less row is no longer grafted onto a holder; that half is fixed. This card is the remaining case.
Why it matters
Whoever customised the losing holder's item (an admin, or an agent through MCP: a tool's runtime create is open, so the row need not come from an older release) sees the customization silently revert after every restart. This is the "silently wrong" class #32997 grades as p1. It needs two installed packages holding the same name, both with a stored row.
Do
- Key the hydration's artifact and slot lookup by
(package, name)for everyPACKAGE_SLOTTED_STORE_TYPEStype, so each stored row lands in its own holder's slot (ADR-0150 D3/D4). - Add a pin over at least
toolandwebhook: two holders, one stored row each, both load orders, then a restart. Each exact address serves its own row, and the bare read refuses 409 naming both. - Coordinate with metadata-protocol: the boot hydration binds a stored webhook row of a name two packages hold by registration or load order; key its artifact lookup by (package, name) (ADR-0150 D3/D4) #32692 (webhook, in flight). If its fix is the same lookup, land it there once and use this card for the remaining types and the pin.
Also carried here: the heal path (added by triage 2026-11-13 evening, from PR #33149 / #32820, review#1 record 6864058135)
Same hydration/heal family, in packages/objectql/src/registry.ts, which is outside #32820's surface. Both items are main's answer and were not moved by that PR. Weight p3 (transient or rare), done after this card's main case.
- Heal 1 (③): a holder that is installed (not re-enabled) after the hydration leaves a package-less overlay row in the other holder's slot until the next unscoped hydration.
- Heal 2 (n1): when no holder is served at the enable, the heal rebuilds through the lookup that names no package and drops its record. If that lookup answers a disabled holder's artifact, the next enable has nothing to rebuild, as the hydrator itself would leave it.
Reader
domain:server. ADR-0150's red lines apply: resolution is never loosened, ambiguity is reported and never guessed, and the change is independently releasable.
Dedupe
boot hydration two stored rows holder: only #32692 (webhook scope, by ruling). PACKAGE_SLOTTED_STORE_TYPES hydration: 0 open. loadMetaFromDb last loaded: 0 open.
Activity
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: grade ·
domain:server· p2 ·pm:queue· 2026-11-13T15:54Z⛔ Not a claim.
docs(objectql): name the follow-up card for two stored tool rows, and…
objectstack-fleet commentedon Nov 14, 2026
epic:#31527#3 · os-tesla · session_01L9qibzECS2npZFku4956Um
Scope note: #32692's half 2 ("one row per holder") is carried by this card · 2026-11-14T01:02Z
⛔ Not a claim. This seat (
epic:#31527#3) owns this card's line (the maintainer's order 6866786021, batch 2).domain:server#7's metadata-protocol: the boot hydration binds a stored webhook row of a name two packages hold by registration or load order; key its artifact lookup by (package, name) (ADR-0150 D3/D4) #32692 thread. metadata-protocol: the boot hydration binds a stored webhook row of a name two packages hold by registration or load order; key its artifact lookup by (package, name) (ADR-0150 D3/D4) #32692 half 1 landed as PR fix(metadata-protocol)!: a stored row bound to a package that holds none of its name, or a pair row of a two-holder name, is no longer laid into the first-registered holder's registry slot (ADR-0150 D4) #33166 (16e34864: the stray-package row is declined; a pair row takes the envelope of the holder it customizes). The maintainer picked C+A on metadata-protocol: the boot hydration binds a stored webhook row of a name two packages hold by registration or load order; key its artifact lookup by (package, name) (ADR-0150 D3/D4) #32692's design card (2026-11-14T01:02Z): C = land the stray fix first, A = the per-package overlay slot as a card of its own on the epic line. This card is that card: its main case is the same "last row loaded wins the name's one bare slot", so no second card is filed (one family, pm-dispatch(grading) + NORTH-STAR: grade in a fixed order — impact, reach discount, one raise, release window — with decidable tests for security boundary, core task, workaround and "a real user can hit" #32997's follow-up rule).bareSlotEntriesOf; the write side and the bare-first readers areregisterItem's key,getItem,listItems, unregister, the delete heal,restoreArtifactRegistryView, and fix(metadata-protocol)!: enabling a second holder of an overlay name takes back the package-less row the read-side hydrator laid into the first holder's registry slot while the second was disabled (ADR-0150 D4) #33149's heal (which compares the bare entry by identity).server-seat-7/r2026-11-13/31699-fable-review.md§2 and32692-redline-review.mdS1 (project files).Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn
Claim: area-lease pilot #33059, area E1 · 2026-11-14T16:05Z
Branch:
claude/area-E1-33127Account:
os-elon-muskClause-②: yes (narrowing)
Metadata-protocol: semantic
Coupled set in one PR: this card (lead), with #32900, #32663 and #32662; #32692's pair-row rule is read, not changed. Owned files beyond the E1 lease:
packages/objectql/src/registry.ts(the stored-row slot model) andpackages/metadata-protocol/src/protocol-registry-hydration.ts. No E1 hot file is edited. Open E2b PRs (#33271, #33274) touch neither file.The narrowing arm: an action held only as stored rows by two packages was served by the read naming no package after a restart (the row hydrated last); it now refuses 409 naming both, as every other type the registry reads by package already did.
objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn
os-dev-report
{ "issue": 33127, "status": "done", "branch": "claude/area-E1-33127", "pr": "https://github.com/objectstack-ai/objectstack/pull/33513", "session": "session_016WV4cy1y7UNVbT2QAdmgdn", "premise_still_valid": true, "summary": "SchemaRegistry kept ONE bare slot per name for a stored row, so the row saved or hydrated last took it; every symptom in #33127/#32663/#32662/#32900 was that slot. A stored row bound to a package (its own, or its .custom pair's by the pair-row rule) of a PACKAGE_SLOTTED_STORE_TYPES type (less flow, permission) now registers in that package's own overlay slot beside the composite entry; every bare-slot reader sees the slots, ranked per package, and the exact read admits a pair address at its stored-row base. Each address serves its own row in every registration/save/row order, before and after a reboot, on writer and peer; the bare read of a two-holder name stays 409 naming both (#32607). One narrowing: an action held only as stored rows by two packages, bare read after a restart, 200 (last hydrated) -> 409 naming both; ADR-0087 semantic entry stored-row-own-package-slot. The slot model also moves #33131's carried face (registry action item with both overrides declared -> each its own override); that pin moved to its TO and #33131 is NOT closed. One PR, ~760 changed lines (no split).", "tests": "Head 8d85d2b1af, all under os-verify-lock. Targeted: objectql 4 files Tests 144 passed (144); runtime meta-disabled-holder-served-stack Tests 36 passed (36); metadata-protocol register-item-call-sites Tests 5 passed (5). Typecheck objectql+metadata-protocol+runtime+spec TC_EXIT=0. pnpm lint LINT_EXIT=0. turbo run test over the 83 dependents of objectql/metadata-protocol/runtime + @objectstack/spec: Tasks 186 successful, 188 total; failed: @object-ui/example-schema-catalog#test 'sh: 1: vitest: not found' (box install, NOT MEASURED) and @objectstack/dogfood#test 2 'Test timed out in 5000ms' under contention ([#31985] bare-name-one-holder-ai-family, [#29414] control package-commit-revert-path-package), both green re-run alone under the lock (VERDICT command-exit 0, Test Files 2 passed, Tests 39 passed). Ablations (ablation-replace.mjs; mp rebuilt; dist-preflight marker present, then restore + rebuild + --absent exit 0; whole tree clean): overlaySlot forced off (ABLATION_33127_SLOT) objectql 27 failed/117 passed = [#33127] boot 16 + [#32663] 6 + [#33131] moved 4 + [#32900] pair-first 1, runtime 2 failed (#33127 doors); storedRowBases off: runtime 4 failed (#32662 pair addresses); one-holder served arm off (ABLATION_33127_PLAINB): runtime 3 failed (#32662 (b) x2 + #32607 M1); isBundleAddition row-only exemption off: objectql 1 failed ([#28802] dependent's member at the same locale). CONTROLs green throughout. First slot/plainb pass used false-&& markers the build folded away (dist preflight exit 1) - re-run with globalThis markers, preflight exit 0.", "gates": "Local: dispatch-gates --commands (102 families on the final diff) all run; exit 0 except check:dual-build-cjs-loads exit 3 'Run pnpm build first' (NOT MEASURED, CI); check:engine-double-contract and check:objectql-double-limit exit 1 on first pass (new unbounded find double) -> fixed + ledger --write -> both exit 0. --ran reconciliation: after the last batch, 0 unrun (the 7 families the ledger edit added were run, all 0). check:adr-0087-registration exit 0 (registered stored-row-own-package-slot). check-nul-bytes OK. PR #33513 check-runs at report time: 19 in_progress (Check Changeset, Lint x8, Type Check x4, Spec property liveness, PR-body guards, Governed Surface Queue Guard, Check PR Size, Flag docs, filter), 5 skipped; not waited on.", "dogfood_battery": "8d85d2b1af · turbo run test (dogfood#test, no shard, no path) Test Files 2 failed | 463 passed | 3 skipped (468) · Tests 2 failed | 3930 passed | 42 skipped (3974) · failures: bare-name-one-holder-ai-family [#31985] and package-commit-revert-path-package [#29414] control, both 'Test timed out in 5000ms' on a contended box; re-run alone under the lock VERDICT command-exit 0, 2/2 files, 39/39 tests", "mcp_calls": "0 this segment (issue_read / pull_request_read reads only, before the context summary); no MCP write tool", "api_writes": "4 — POST issues/33127/comments (claim, via post-stamped relay), git push (branch), pr_create #33513 (fleet-write relay), POST issues/33127/comments (os-dev-report, via post-stamped relay)", "open_questions": [ { "question": "#33127's body also lists heal 1, heal 2 and S1. The slot model makes restoreArtifactRegistryView retire the removed package's slot, but those three items are not separately pinned here, and the PR body's closing line for this card closes it on merge. Keep Fixes or downgrade to Part of?", "options": [ "A keep the closing line; file heal 1/heal 2/S1 as a follow-up sub-issue if the seat finds them still open", "B change the closing line to a Part-of line (seat-written edit) and leave the card open for those items" ], "recommendation": "B if the seat reads heal 1/heal 2/S1 as separate acceptance criteria (the body has no pins for them); A otherwise" }, { "question": "The coordinator's pre-push rule (tests of touched packages plus all dependents, pnpm lint) conflicts with os-dev's 'repo-scale runs are CI's'. I followed the coordinator but narrowed the dependents to the 83 reached through code (objectql/metadata-protocol/runtime) plus spec, leaving the 39 packages reached only through the new spec migration entry to CI. Accept the narrowing?", "options": [ "A accept (declared narrowing)", "B require the full 122-package affected set locally" ], "recommendation": "A: the spec change is one semantic-entry file read only by spec's migration registry, and the 83+spec run held the lock 3h30m on a shared box" } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: #32663 residual (a) · dashboard stays converged by name in the registry (one bare slot); #32451 CONTROL kept; awaits its ruling · noted, not filed", "carrier: #33131 · its carried face (registry action item with both overrides) is now each holder's own override; pin moved to TO; seat to judge whether the card closes · noted, not filed", "carrier: none · getMetaItemLayered at a pair address is unchanged (only the plain read adopts storedRowBase) · Acceptance notes only", "carrier: none · dogfood [#31985] bare-name-one-holder-ai-family ran 5011ms under contention against vitest's 5000ms default; green alone · Acceptance notes only" ], "schema_registry_symbols_changed": "registerItem (5th arg options.storedRowPackage), bareSlotEntriesOf, rankedForPackage (new, private), orderedOverlayTier (new, private), removePackageOverlaySlots (new, public), getItem, getPackageScopedItem, overlaySlotBinding, boundServedActions, unregisterItem, packageScopedHoldersOf, ownersHoldingAName, isBundleAddition (3rd arg codeMembersOf); module helpers OVERLAY_SLOT_MARK, overlaySlotKey, parseOverlaySlotKey, overlaySlotEntriesOf, storedRowPackageOf. E2b overlap: none — open E2b PRs #33271 (plugin.ts, action-handler-coordinate.ts) and #33274 (runtime action-execution.ts) touch no file of this PR; #33271 reads composite keys, which this change leaves as they were.", "deviations": "Coordinator pre-push rule followed with the declared narrowing above. Branch was not pushed empty first (the coordinator rule gates every push on the dependents' run); the first push carried the finished, tested head. A first ablation pass for two arms was void (marker folded by the build) and re-run, both legs recorded." }