Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/7175-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
---
---

Docs-only: records the downstream-consumer census for
`@object-ui/plugin-detail`'s `PointInTimeRestore` as
`docs/audits/2026-09-plugin-detail-downstream-consumer-census.md` (objectui#7175).

objectui#7163 measured that the component has zero *in-repo* consumers. That is not the
same statement as zero consumers, because it is barrel-exported public API, so this audit
reads the downstream populations instead: `hotcrm` measured at `a6be39a3d` (zero on every
spelling, against a positive control of 104 `plugin-detail` node references in the same
repo on the same instrument), and `cloud` reported as **NOT MEASURED** — refused on three
independent channels, two of them beside a live control.

No source, behaviour, or public-surface change; the audit records evidence so the
ADR-0049 enforce-or-remove question can be decided later. It deliberately retires nothing.
194 changes: 194 additions & 0 deletions docs/audits/2026-09-plugin-detail-downstream-consumer-census.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
# Audit: downstream consumer census — `PointInTimeRestore` and the `plugin-detail` barrel (2026-09)

**Question** (objectui#7175): does anything *outside this repo* render
`@object-ui/plugin-detail`'s `PointInTimeRestore`?

**Why it exists**: objectui#7163 / PR #7172 measured that `PointInTimeRestore` has **zero
in-repo consumers** — barrel-exported only, no mount point anywhere in `objectui`. That
measurement was correct but it is *not* the question ADR-0049 enforce-or-remove needs
answered, because **"zero in-repo consumers" is not "zero consumers."** The component is
published public API; a downstream application may render it. This audit takes the
reading the in-repo one could not.

**Populations**: `objectstack-ai/hotcrm`, `objectstack-ai/cloud`.

⛔ **This audit does not retire anything.** Retiring a published component is
ADR-0049 / ADR-0087 (objectstack) and narrows public surface. This is the measurement that
makes that decision *possible*, not the decision.

---

## Summary

| Population | Channel | Positive control | `PointInTimeRestore` | Verdict |
| --- | --- | --- | --- | --- |
| `objectui` (in-repo, re-confirmed) | local worktree @ `899730e0a` | `RecordComments` mounted 2x in `DetailView.tsx` | 0 mounts | unrendered here (confirms #7163) |
| `hotcrm` @ `a6be39a3d` | anonymous shallow git clone | **HIT** — 104 `plugin-detail` node references | **0 on every spelling** | **zero — measured** |
| `cloud` | none reachable | n/a | n/a | ⚠️ **NOT MEASURED** |

**Headline**: no measured consumer, anywhere, renders `PointInTimeRestore` — and in
`hotcrm` it is not merely absent, it is **structurally unreachable** (see below). One
population, `cloud`, could not be read at all and is reported as its own category.

⚠️ **NOT MEASURED is not zero and not green.** `cloud` is unread, not clean.

---

## Channel evidence

Each clone's exit code was captured **before any pipe**, beside a same-shape control.

| Command | Exit | Reading |
| --- | --- | --- |
| `git clone --depth 1 .../hotcrm.git` | **0** | 828 tracked files at `a6be39a3d` |
| `git clone --depth 1 .../objectui.git` (control) | **0** | 6039 tracked files at `899730e0a` |
| `git clone --depth 1 .../cloud.git` | **128** | `could not read Username` — auth wall |
| `git ls-remote .../cloud.git` | **128** | same wall, second command shape |
| `git ls-remote .../hotcrm.git` (control) | **0** | refs listed |
| session repo-attach for `cloud` | error | `you don't have access to objectstack-ai/cloud` |

`cloud` was refused on **three independent channels**, two of which returned a live
control in the same breath. It is unreadable from this seat, not empty.

---

## The reachability argument — stronger than the grep

`hotcrm` is a **metadata application**. It declares UI as JSON-ish metadata rendered by
objectui; it does **not** import objectui as a library:

- `@object-ui/*` appears in exactly **3** `hotcrm` files, and all three are **prose
comments** (`crm.app.ts:169`, `account_detail.page.ts:32`,
`scripts/analytics-reconcile/macros.ts:5`).
- Real imports of any `@object-ui` package: **0**. `hotcrm`'s `package.json` depends on
`@objectstack/*` only.

So the only channel by which `hotcrm` can reach an objectui component is a **registered
component type string** in metadata. And:

> `PointInTimeRestore` is **never** passed to `ComponentRegistry.register`. `plugin-detail`
> makes 16 registrations; none of them is this component. There is no auto-registration —
> no `Object.entries(...)`/`forEach(register)` pattern exists in the barrel (0 hits).

⇒ `PointInTimeRestore` **has no type string**, so a metadata app cannot name it. The zero
below is therefore not a lucky grep; it is what the architecture requires.

---

## The `hotcrm` reading

**Positive control — same repo, same instrument, same channel** (`plugin-detail`
components that `hotcrm` actually mounts):

| Node type | References in `hotcrm` |
| --- | --- |
| `record:details` | 31 |
| `record:related_list` | 21 |
| `record:highlights` | 17 |
| `record:activity` | 16 |
| `record:path` | 12 |
| `record:chatter` | 4 |
| `record:history` | 3 |
| **total** | **104** |

The instrument resolves 104 references to *this very package* in *this very repo*. It is
productive here, so a zero from it is a reading.

**Target — every spelling, all zero:**

| Spelling probed | Hits in `hotcrm` | Same probe in `objectui` (control) |
| --- | --- | --- |
| `point[-_ ]?in[-_ ]?time[-_ ]?restore`, case-insensitive | **0** | 26 |
| `PointInTimeRestore` exact identifier | **0** | 26 |
| `PointInTimeRestoreProps` | **0** | 3 |
| `RevisionEntry` (the co-exported type) | **0** | 5 |
| loose `point[-_ ]?in[-_ ]?time` | **0** | 30 |
| `import(...PointInTime...)` lazy form | **0** | 0 |
| `plugin-detail` package specifier | **0** | 870 |

The separator/case-insensitive pattern covers named import, namespace member, re-export,
kebab (`point-in-time-restore`), snake (`point_in_time_restore`) and camel spellings in
one shot. **The identical pattern set returns 26 hits in `objectui`** — the probes fire.

**Every semantic near-miss attributed.** One hit for `snapshot.*restore`:
`test/forecast-manual-override.test.ts:279` — *"deleting the manual row restores automated
snapshotting"*. Forecast snapshots, unrelated to revision history. Not a render.

Non-zero hits for sibling *identifiers* (`DetailSection` 4, `CommentInput` 3, and so on)
were each read: all are prose comments, test docstrings, or `@objectstack/spec/ui` type
names such as `RecordRelatedListProps`. Since `hotcrm` has zero objectui imports, none can
be a render.

---

## Bonus: `PointInTimeRestore` is not an isolate

Once the instrument answers "is X reachable", it answers it for X's siblings for free. Of
`plugin-detail`'s **29** component-shaped barrel exports, **7** are neither registered
(no metadata type string) nor mounted anywhere in this repo:

| Unregistered **and** unmounted | Registered? | In-repo mounts |
| --- | --- | --- |
| `CommentInput` | no | 0 |
| `DiffView` | no | 0 |
| `InlineCreateRelated` | no | 0 |
| `MentionAutocomplete` | no | 0 |
| **`PointInTimeRestore`** | no | 0 |
| `RecordNavigationEnhanced` | no | 0 |
| `RelationshipGraph` | no | 0 |

None of the seven has a dynamic reference either (`React.lazy`, `createElement`, or a
string literal of its own name): 0 for all seven.

⇒ `PointInTimeRestore` is the **visible instance of a seven-member class**, not a one-off.
That is the difference between one retirement card and an enforce-or-remove ledger. This
audit does not act on the other six; it records them.

⚠️ Unmounted is **not** the same as unreachable-and-dead. `RecordComments` is also
unregistered, yet `DetailView` mounts it directly at `:1479` and `:1705` — a component can
be perfectly live through a sibling's JSX without ever having a type string. The class
above is specifically *both* doors closed.

---

## Method — re-runnable, and its one recorded failure

Deliberately **not committed as a test**: it clones external repositories, so it cannot
run in CI, and a committed test that cannot run renders as coverage while measuring
nothing (objectui#7183). It is recorded here instead, to be re-run by hand.

```bash
git clone --depth 1 https://github.com/objectstack-ai/hotcrm.git /tmp/hotcrm # exit BEFORE any pipe
# controls first, target second; every count printed as an integer, never blank
grep -rIF --exclude-dir=.git 'record:details' /tmp/hotcrm | wc -l # expect > 0
grep -rIE --exclude-dir=.git -i 'point[-_ ]?in[-_ ]?time[-_ ]?restore' /tmp/hotcrm | wc -l
```

⚠️ **Two instrument traps, both hit during this audit.**

1. `git grep -c` prints **nothing**, not `0`, on no match. Every count above is piped
through `wc -l` so a zero is always a printed integer.
2. The in-repo mount probe first used `<Name[[:space:]/>]` and reported **0 mounts for
`RecordComments`** — a component known to be mounted twice. Cause: grep is
line-oriented and these JSX tags end the line (`<RecordComments` with props on the
following lines), so the trailing character class could never match. Fixed to
`<Name($|[[:space:]/>])`, which returns the expected 2. **The whole sibling table was
re-derived after the fix and gated on that control passing.** A probe that cannot see
its own known-positive is not measuring.

Counts are from `main` at audit time — a baseline, not a frozen census.

---

## What this audit does NOT claim

- ⛔ Not that `PointInTimeRestore` should be retired. That is ADR-0049 / ADR-0087, it
narrows public surface, and it is a decision this audit only makes *possible*.
- ⛔ Not that `cloud` is clean. `cloud` is **unread**.
- ⛔ Not that the other six unmounted exports are dead. They are unmounted and
unregistered *here*; they have had no downstream census of their own.
- ⛔ Not that PR #7172's i18n sweep was wrong. It was reviewed and upheld.

Refs: objectui#7175 (this census) · objectui#7163 / PR #7172 (the in-repo measurement and
the sweep) · objectui#7183 (why this is not a committed test) · objectstack ADR-0049,
ADR-0087.