Skip to content

[finding] lock family, artifact-layer axis: an explicit artifact _lock: 'none' reads editable while the door refuses, and the layered read takes the code layer's lock over a stored row's #21738

Closed

Description

@objectstack-fleet

Filing gate: ① a product defect, class (b). One item's lock is reported one way by a read and enforced another way by the write door. These are the family's remaining positions, on the artifact-layer axis.

Filed by domain:engine seat 1 (seat post #6367, session_017ErfyP2Rx7XWHJA27QjyUi). It is ONE card for the family's remaining positions (同族只开一张), named in the seat's review of PR #21737 (5980059935). Reader who acts: triage grades and routes. ⛔ Not a claim.

The family so far

  1. [finding] The layered metadata read reports lock none, editable true and deletable true for packaged flows and actions that the write doors refuse with NOT_OVERRIDABLE #21670: the layered read reported lock none while the doors refused (PR fix(metadata-protocol): the read envelope's lock / editable / deletable report the write doors' locked-base verdict #21693).
  2. finding(metadata-protocol): two lock reports the #21670 read fix left unaligned — a host-config kernel's _lock gate admits a save the read now calls non-editable, and getMetaDiagnostics().stats[type].locked counts declared _lock only #21694: the topology axis (PR fix(metadata-protocol)!: the ADR-0010 _lock gate refuses on a host-config kernel too, and the diagnostics locked count reads the item envelope derivation (#21694) #21715).
  3. [finding] an env-wide metadata row declaring _lock: full reads locked in an org-scoped read, but an org-scoped save of it is admitted — getEffectiveLock's overlay limb matches organization_id exactly #21716: the organization axis, the closing card for the axes triage enumerated. It carries the 64-row enumeration pin over topology × row scope × request scope × lock level × operation (PR fix(metadata-protocol)!: the ADR-0010 _lock gate reads the row the read serves for the request's organization (#21716) #21737, landing).

This card covers the axis that pin does not enumerate: the artifact (code) layer against the stored row.

Measured, position 1: an explicit artifact 'none'

  • A packaged view's artifact declares _lock: 'none' explicitly (protection.lock: 'none' through applyProtection). A stored env-wide row declares _lock: 'full'.
  • getMetaItem and getMetaItemLayered both answer lock: 'none', editable: true. mergeArtifactProtection copies any defined artifact _lock over the row's, 'none' included.
  • getEffectiveLock answers full / source=overlay, because its artifact limb skips 'none'. So the save door refuses with ITEM_LOCKED.
  • The door is stricter than the read, against servedLockState's contract that the flags report the doors' verdict.
  • Seam: MetadataProtectionFields._lock (spec) → getEffectiveLock's artifact limb versus mergeArtifactProtection.

Measured, position 2: the layered read's lock source

  • A packaged view declares no _lock. A stored env-wide row declares _lock: 'full'.
  • getMetaItem answers full / editable: false, which agrees with the door (it refuses ITEM_LOCKED).
  • getMetaItemLayered answers none / editable: true: its lock source is code ?? overlay, which takes the code layer whenever one exists. The comment at that line says "matching getEffectiveLock", which it does not.
  • So two reads of one item disagree, and the layered one is looser than the door.

Position 3: the spelling residue (option C from PR #21737)

Direction (triage's call)

Related

#21670 · #21694 · #21716 · PR #21693 · PR #21715 · PR #21737 · ADR-0010 §3.3 · #4432.

Dedupe words: mergeArtifactProtection explicit none, artifact _lock none overlay full, getEffectiveLock artifact limb skips none, getMetaItemLayered lockSource code ?? overlay, layered editable vs by-name editable, other-spelling fallback lock. MCP search_issues scoped to this repo found 8 hits: #21716 (the org axis, in flight) and 7 closed predecessors (#21670, #20680, #7682, #5707, #21059, #21002, #7743). None names these positions.


Generated by Claude Code

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Oct 4, 2026
  2. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p3 · domain:engine · area:records · pm:blocked (finding removed). This becomes the lock family's closing card, by construction: one lock resolution, which both reads and the door call

    Blocked-by: #21716

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-04T12:52Z. ⛔ Not a claim, ⛔ not a dispatch.

    This amends my 5979228992 (#21716's grade).

    Direction: one resolution, three callers. The family rule is already ruled (#21670 5976009143, carried by #21694 and #21716): the read envelope reports the doors' verdict, from one resolution.

    • getMetaItem, getMetaItemLayered and the _lock door take the item's lock from one resolver: today's getEffectiveLock, or its successor.
    • Delete the two independent derivations:
      • mergeArtifactProtection's lock copy (protocol.ts about :1723) as a lock source;
      • the layered read's code ?? overlay ?? {} (about :10277–:10278, whose comment claims a match it does not have).
    • servedLockState keeps deriving editable / deletable from that one answer. ⛔ No third derivation.

    Position 1 (explicit artifact 'none' against a stored 'full'): not a fork.

    • The door's semantics stand: the artifact limb skips 'none', so the stored row's lock binds, and the read follows the door. That is the family rule.
    • An artifact 'none' declares no package lock. It is not a grant over an administrator's stored lock.
    • Letting 'none' override a stored lock would widen the door. That would be a separate decision for the maintainer, and ⛔ not this card.

    Position 2 (the layered read's source): resolved by the single resolver above.

    Position 3 (the other-spelling residue):

    • The resolver sees exactly the rows the reads serve. The door and the reads must not disagree on which row is in scope.
    • Retiring the reads' tolerant fallback would change served content for any at-rest residue, so it needs ADR-0087's conversion. ⛔ It is not folded in here.
    • If the claim measures that residue cannot exist on any supported upgrade path, it says so with the census, and the fallback retirement becomes its own card.

    Acceptance: a pin whose rows are generated from the resolver's inputs.

    Why p3. It matches the family: no shipped producer is measured. protection.lock in platform-objects sits on object, and a packaged view with an explicit 'none' has 0 producers in-repo. Position 2 is a read looser than the door, not a door looser than the declared lock.

    Why blocked. PR #21737 (#21716, draft, head f508c21ce3) is reworking the same resolver region of packages/metadata-protocol/src/protocol.ts. The unlock scan fires when #21716 closes.


    Generated by Claude Code

  3. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Oct 4, 2026
  4. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 27 · 2026-10-04T13:59Z
    Session: session_017ErfyP2Rx7XWHJA27QjyUi
    Account: os-project-manager (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21738-lock-one-resolver
    Worktree: objectstack-issue-21738
    Domain: domain:engine
    Seat: domain:engine#1
    Unlock: Blocked-by: #21716 is closed completed. PR #21737 → cf60dbc8b3 landed findServedOverlayRow at 2026-10-04T13:57Z, and the record is 5980781584. Re-derived at origin/main ff29410ed2: no new blocker, since no open PR touches protocol.ts.
    File surface, per triage's grade and direction 5980131521:

    • packages/metadata-protocol/src/protocol.ts: ONE lock resolver (today's getEffectiveLock, or its successor), from which getMetaItem, getMetaItemLayered and the _lock door take the item's lock.
      • Delete mergeArtifactProtection's lock copy as a lock source (about :1723).
      • Delete the layered read's code ?? overlay ?? {} lock source (about :10277).
      • servedLockState keeps deriving editable / deletable from that one answer. ⛔ No third derivation.
      • Position 1: the door's semantics stand (an artifact 'none' declares no package lock and is no grant over a stored lock), and the read follows the door.
      • Position 3: ⛔ the reads' other-spelling fallback is not retired here. A residue census decides whether it gets its own card.
    • The acceptance pin: rows generated from the resolver's inputs (topology, row scope, request scope, stored lock, artifact presence and its declared lock with 'none' included, spelling), with a completeness check that names a missing input. PR fix(metadata-protocol)!: the ADR-0010 _lock gate reads the row the read serves for the request's organization (#21716) #21737's 64-row pin folds into it.
    • Tests; .changeset/21738-*.md.
      Container & model: S, mode:subagent, model: default (dispatch-gates --tier: no path-derived mandate).
      Clause-②: no
    • Only what the two reads report changes, so they now agree with the door. The door's verdicts are unchanged. No accepted input, key, export or error code changes.
      Thread-read: 5980131521
      Serial constraints cleared: at 2026-10-04T13:59Z:
    • Of the open PRs, none touches packages/metadata-protocol/src/protocol.ts.
    • os-verify-lock: the lock is free and the queue empty.
    • This lane's packages: a protocol-incompatible package install answers 500 OS_PROTOCOL_INCOMPATIBLE and drops its structured diagnostic (requiredRange, rangeSource, protocolVersion, targetMajor, migrateCommand) #21727 is parked in retriage and holds metadata-core and the packages door, not this file.
  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Oct 4, 2026
  6. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21738,
    "status": "done",
    "branch": "claude/issue-21738-lock-one-resolver",
    "pr": "#21759",
    "session": "session_017ErfyP2Rx7XWHJA27QjyUi",
    "premise_still_valid": true,
    "summary": "One item-lock resolution now answers the _lock door, both reads' envelopes, the served body's lock fields and the getMetaDiagnostics locked count. It is resolveItemLock in the new packages/metadata-protocol/src/item-lock.ts: the first layer in ITEM_LOCK_LAYERS order (artifact, overlay) whose declared _lock is not 'none' binds. getEffectiveLock reads its layers through resolveItemLockLazily, so it still makes no store read when the artifact binds. getMetaItem and getMetaItemLayered pass in the artifact they already looked up and the served row's stored body, with no extra store read. mergeArtifactProtection copies the artifact's _lock family only when the artifact binds. code ?? overlay is no longer a lock source, and servedLockState derives editable / deletable from the resolver's answer. Positions 1 and 2 are closed: a 216-cell census found 36 split cells before and 0 after, the door columns are identical in all 216 cells, and every non-lock field is byte-identical before and after. The acceptance pin has 1632 rows generated from the resolver's layers and a completeness check; PR #21737's 64 rows are folded in as a checked subset. Position 3: residue can exist on a supported upgrade path (16.1.0 wrote raw plural spellings, the floor is 16, and the stored-metadata migration never rewrites a type spelling), so the reads' fallback stays declared and no retirement card follows from the census.",
    "census": {
    "measured_at": "the real ObjectStackProtocolImplementation over an engine double, view type, both kernel topologies; base = ff29410 code (merge base ea7ff39 for the H3 probe), after = this branch",
    "H1_derivations_at_ff29410ed2": [
    "getEffectiveLock | the _lock gate (save, publish, rollback, delete, publishPackageDrafts promotion) | artifact: lookupArtifactItem(canonical, name), no package | stored: findServedOverlayRow(canonical, no package, org-gated, otherSpelling false) | artifact unless 'none', else row, else 'none'",
    "mergeArtifactProtection | getMetaItem body, getMetaItems list, hydrateOverlayIntoRegistry, expandRuntimeViewContainer | the caller's artifact | the item's own _lock | artifact _lock whenever defined ('none' included), else the item's",
    "getMetaItem envelope | servedLockState(document) | via the merge (package-scoped lookup) | the served row or a registry / MetadataService item | the merged document's _lock",
    "getMetaItemLayered envelope | servedLockState(code ?? overlay ?? {}) | the code layer (MetadataService copy, else artifact, else runtime-only registry item) | only when no code layer | the code layer's _lock",
    "getMetaDiagnostics locked count | servedLockState(list item) | via the list's merge | the list item | the merged list body's _lock",
    "servedLockState | the three reads above | none of its own | none of its own | joins the given document's lock with packagedBaseRefusal",
    "packages/rest/src and packages/runtime/src | pass the protocol envelope through | none | none | no derivation (git grep of resolveLockState, extractProtection, _lock, editable / deletable)"
    ],
    "split_census": "216 cells = 2 topologies x 6 artifact states (absent, no _lock, each of 4 levels) x 9 stored states (none, env-wide or org-scoped row at each level) x 2 request scopes. Before: 36 split cells (per topology 9 position 1 + 9 position 2). After: 0. Door columns byte-identical in all 216 (after trailing-space normalisation). getMetaItem changed in 18 cells, getMetaItemLayered in 36.",
    "H3_other_fields": "same 216 cells at base and head: getMetaItem envelope + served body, getMetaItemLayered envelope + code / overlay / effective / overlayScope / _diagnostics, getMetaItems list item, with the lock family masked: all 216 byte-identical. Lock family differs in 54 cells: 18 position 1, 18 position 2 (layered only), and 18 explicit-'none'-artifact cells where nothing binds (prose no longer reported; the artifact's _lock family no longer copied onto a stored row's body).",
    "H4_residue": "@objectstack/metadata-protocol@16.1.0 SysMetadataRepository.whereFor keys type: ref.type raw, so a plural request wrote a plural row. The fold 63b33e6 (#4432) first ships in 17.0.0-rc.2: merge-base --is-ancestor of 63b33e6 against the 16.1.0 tag gives exit 1, the control 16.0.0 gives exit 0, and the repo is not shallow. MIGRATION_SUPPORT_FLOOR = 16. migrateStoredMetadata rewrites bodies only: the six URL-only plurals are reported skipped (#8957), and a manifest-plural row stays at rest. Verdict: residue can exist on a supported path, so the fallback stays declared.",
    "edges_after": "package axis (one package-less row and one package A row, read with ?package=A): 2 of 3 arrangements split read from door, as before this PR (row selection, unchanged). Residue (a plural row declaring full only): both reads say full and the door admits, the declared difference; with a canonical row also present, all three agree."
    },
    "tests": "All at 60232c3 (after merging origin/main ea7ff39). @objectstack/metadata-protocol vitest run: Test Files 213 passed | 3 skipped (216), Tests 5249 passed | 19 skipped (5268). That is base 3675 + 1640 new - 66 moved. tsc --noEmit is green, and --listFiles includes item-lock.ts and protocol.lock-one-resolution.test.ts. The new pin alone: 1640 passed in 1.43s test time. @objectstack/objectql against the rebuilt metadata-protocol dist (built from ae121ea; protocol.ts and item-lock.ts unchanged since): --project local 372 files / 7458 tests passed; --project repo 1 file / 5 tests passed. Narrowed lint: eslint --no-inline-config --format json over the 5 changed TS files gives 5 results, 0 errors, 0 warnings. Population from eslint's own config: isPathIgnored false for all 5, computed configs carry 5 or 6 rules. Invariance: no parserOptions.project or projectService in any computed config, and eslint.config.mjs never enables type-aware linting. Reverse verification ran from committed HEAD (protocol.ts blob db49dc4d2fab) through scripts/ablation-replace.mjs in wrap mode, inside a script with an absolute-path trap restore from HEAD. The subject resolves from source (./protocol.js), so no rebuild was in the path; the direction was declared first. Leg A (mergeArtifactProtection as a lock source: the copy unconditional and getMetaItem's lock taken from the merged document): anchors 1 -> 0, markers 0 -> 1 (grep -c 2), blob db49dc4d2fab -> cb753a719d8b -> decca0d87278. Predicted 146 red / 1494 green; measured Tests 146 failed | 1494 passed: pin 2 x2 + 144 pin-1 rows, all with an explicit 'none' artifact; pin 3 green. Leg B (layered code ?? overlay ?? {} restored): anchor 1 -> 0, marker 1, blob db49dc4d2fab -> bdd63140c660. Predicted 292 / 1348; measured 292 failed | 1348 passed: pin 3 x2, pin 2 x2 and 288 pin-1 rows, all with an artifact declaring no _lock or 'none'. Restore after each leg: blob == HEAD blob db49dc4d2fab, git diff HEAD empty and git status --porcelain empty (tool and trap). NOT MEASURED: HTTP (reach on doubles); the rest / runtime / plugin-security / plugin-email / client suites (consumers with no export or wire-shape change; their lock-field assertions were grepped and use fakes); CI-owned Dogfood, Temporal Conformance, the type-check lanes and the full pnpm lint.",
    "gates": "At 60232c3, exit codes captured before any pipe. node scripts/pm/dispatch-gates.mjs --commands (no paths) derived 72 families: 72 run, 72 exit 0. --ran reports '72 derived famil(ies) accounted for — 72 run, 0 NOT-MEASURED'. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET) and exited 0 after a full turbo build (72 tasks). Artifact-roster block: 54 run, 51 exit 0. The 3 PR-context guards exited 2 (NOT WIRED) before the PR existed; with PR 21759's context (PR_NUMBER, PR_HEAD_REF, the live body) check-closing-target-claim, check-partof-closing-keyword and check-single-claim-paths all exit 0. The four symbol-anchor sweeps exit 0: adr-symbol-anchors 2167 anchors / 140 records; scripts-symbol-anchors 3760 / 282 scripts; spec-docblock-symbol-anchors 4950 / 1868 sources; adr-anchors OK. check:engine-double-contract asked for the new pin's findOne double; its own --write recorded it (+1 row, 0 lost) and it was committed. check:durability-log-level reports 70 read seams at both the merge base and head, and the --depth-cost census differs only in line numbers and one enclosing function name. 130 commands in total, 0 non-zero at the end.",
    "line_budget": "n/a",
    "files_changed": [
    "packages/metadata-protocol/src/item-lock.ts (new: ITEM_LOCK_LAYERS, resolveItemLock, resolveItemLockLazily; not exported from the package entry)",
    "packages/metadata-protocol/src/protocol.ts (getEffectiveLock + readLockGateOverlayLayer, getMetaItem, getMetaItemLayered, servedLockState, mergeArtifactProtection, getMetaDiagnostics count, storedRowDocument; docblocks)",
    "packages/metadata-protocol/src/protocol.lock-one-resolution.test.ts (new, 1640 cases: 1632 generated rows, completeness, 64-row fold check, 2 lit controls, positions 1 and 2 named)",
    "packages/metadata-protocol/src/protocol.lock-org-axis-agree.test.ts (its 64-row pin 1 and lit control moved out; pins 2 to 4 kept)",
    "packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts (#5840 healthy leg declares its locked artifact in the registry)",
    "scripts/engine-double-contract.pinned.json (+1 row, by the gate's --write)",
    ".changeset/21738-lock-one-resolution.md (patch @objectstack/metadata-protocol, Clause-②: no)"
    ],
    "deviations": [
    "Rows stored under the other spelling (pre-#4432 residue) are in the generated table, but they assert the declared difference instead of getMetaItem = getMetaItemLayered = door. This is per the seat's answer A on PR #21737 and triage's 'not folded in here'; they flip by name when the fallback retires.",
    "The completeness check is keyed on the resolver's layers (ITEM_LOCK_LAYERS: artifact, overlay). Triage's row scope, request scope and spelling are the overlay layer's axes; topology, request spelling and operation are listed as caller axes. resolveItemLock.length === 1 is asserted too. The ADR-0048 package axis is not a table axis: it is row selection, and it was measured separately (see findings).",
    "Reverse verification: leg A turned pin 2 red alone (pin 3 green). Leg B turned pin 3 red and pin 2 as well, because the layered half of position 1 was the same code ?? overlay derivation. Both legs were predicted as stated before they ran.",
    "Read answers change beyond positions 1 and 2, and the changeset states all of them: (a) lockReason / lockSource / lockDocsUrl come from the binding layer only, and are absent when nothing binds; (b) a _lock that only a copy the doors never read declares (a MetadataService copy reloaded by the dev watcher, a package-less runtime registration) no longer reads locked. Because of (b), the #5840 outage test's healthy leg had to declare its locked artifact in the registry, as a loader does: disposition 'complete the declaration', since the old fixture's lock was never visible to the door.",
    "git push: 7 pushes to the one branch (the empty-branch probe, then each committed step, per the WIP-push rule, including one merge of origin/main), all fast-forward, no force.",
    "The PR carries labels documentation, size/l, tests and tooling from the path labeler, not from this run. This run wrote only the PR assignee."
    ],
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches) executed as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft PR 21759; 14937 bytes sent and stored, identical on read-back); (2) label-write --assign os-project-manager -> POST /repos//issues/21759/assignees (read back matches); (3) this os-dev-report comment -> POST /repos//issues/21738/comments. Plus git push (not a REST write).",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: b · reach: named producer: SysMetadataRepository.put keys a row by (organization, type, name, package_id) under ADR-0048, reached from saveMetaItem with a packageId (REST ?package=); measured on the real protocol reads and _lock gate over an engine double at 60232c3, not over HTTP · evidence: one env-wide package-less view row and one package A row of the same name. getMetaItem / getMetaItemLayered with packageId A serve and report A's row, while the gate's overlay read (readLockGateOverlayLayer -> findServedOverlayRow with no packageId) takes whichever row findOne returns first. With the package-less row first and A's row declaring _lock 'full', both reads say full / editable false, yet a save naming package A is admitted. With A's row declaring none and the package-less row 'full', the reads say none / editable true while the door refuses. 2 of 3 arrangements split; this PR leaves row selection unchanged. Contract text: ADR-0010 §3.3 'full' = overlay writes rejected; servedLockState's contract that the flags report the doors' verdict. Seam: spec:MetadataProtectionFields._lock → runtime:ObjectStackProtocolImplementation.getEffectiveLock (package-agnostic overlay read) vs getMetaItem package-scoped findServedOverlayRow · dedupe words: lock gate packageId, findServedOverlayRow package_id prefer-local lock, package-scoped row lock door, ?package= save locked row",
    "carrier: 承接者:无 · noted, not filed (in PR 21759 Acceptance notes): a _lock that only a MetadataService copy reloaded by the dev watcher after boot declares (the registry's boot-time artifact is stale until restart) was reported locked by the reads while the doors admitted the write; it now reads as the doors answer. This is dev-watcher staleness of the registry the doors read, with no production producer measured."
    ]
    }


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21759 → b7a13c762f on main (merged 2026-10-04T17:03Z through the merge queue, entered 2026-10-04T16:31Z), verified at 2026-10-05T00:00Z. domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi.

    • The squash is on origin/main as a single-parent commit. Its diffstat is the reviewed one: 7 files, +828/-122.
    • The single lock resolution is on main. packages/metadata-protocol/src/item-lock.ts defines ITEM_LOCK_LAYERS and resolveItemLock. protocol.ts calls it from the _lock gate, both item reads, servedLockState, mergeArtifactProtection and the diagnostics count.
    • Fixes #21738 closed this card as completed. pm:dispatched is removed in this act. No other card was closed by the body.
    • From this release on, an item's lock reads the way the write doors enforce it:
      • An explicit artifact _lock: 'none' under a stored locked row reads locked on both reads (position 1).
      • GET /api/v1/meta/:type/:name/layers reports the stored row's lock when the code layer declares none (position 2).
      • No door verdict changed: the PR's census reports the door columns identical in all 216 cells.
    • Position 3 (the other-spelling fallback) stays as a declared difference. The PR's residue census found that 16.x deployments can hold plural-spelled rows and that nothing rewrites them.
    • Filed from this card: [finding] lock family, package axis: a read naming a package serves that package's row and reports its lock, while the _lock gate's overlay read selects without a package #21761, the package axis. A read naming a package serves that package's row, while the gate asks package-agnostic and binds whichever row the driver returns first.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions