docs: wiki staleness sweep (Fable-orchestrated Opus audit)

Audited all 40 docs/ against the live codebase; fixed factual staleness in 23,
14 were clean. Highlights (all verified against code):
- equipment -> machines (ADR-011 rename) in INSTALL/DEPLOY-WINDOWS-IIS,
  PLUGIN-GUIDE, GE-ENFORCE, ROADMAP.
- Versions refreshed: contract 0.10.0 -> 0.13.0, product 0.5.0 -> 0.7.0, plus
  plugin example core_version pins.
- Bundled set corrected to the current 13 (PLUGINS.md 7 -> 13 rows; DEPLOY
  eleven -> thirteen).
- Per-plugin Alembic chain workflow (ADR-008) replacing stale core-chain steps
  in PLUGIN-QUICKSTART / BACKUP-RESTORE; deploy adds plugin upgrade-all.
- Frontend plugin staging (ADR-010) replacing 'no frontend plugin system yet'
  in PLUGIN-GUIDE; view/route paths repointed to plugins/<name>/frontend/.
- Corrected file paths (MapView.vue, manifest_schema.json), CLI (shelf-list),
  API gating (GET /api/plugins is optional-jwt), WJF 15 -> 16 stages, and
  retired Collector/PC-Types settings pages (ADR-012).
- ge-enforce proposal marked ACCEPTED/built.
This commit is contained in:
cproudlock
2026-07-19 12:54:53 -04:00
parent 49a0206b9f
commit e005d1846a
26 changed files with 145 additions and 84 deletions

View File

@@ -78,7 +78,7 @@ plugin's identity (ADR-002):
Two fields deserve attention.
`core_version` is a semver range against the framework's `__contract_version__`
(declared in `shopdb/__init__.py`, currently `0.6.0`). The loader refuses to load
(declared in `shopdb/__init__.py`, currently `0.13.0`). The loader refuses to load
a plugin whose range excludes the running framework. We pin `>=0.6.0` because this
plugin uses the `get_reports` hook, which was added to the contract in 0.6.0
(see [PLUGIN-HOOKS.md](PLUGIN-HOOKS.md), "get_reports"). We cap at `<1.0.0` because
@@ -272,7 +272,7 @@ assertion to a frozen `CUTOVER_PLUGINS` list rather than to all discovered plugi
and to expect `measuringtools`'s real baseline revision in the upgrade-all test:
```python
CUTOVER_PLUGINS = ('computers', 'employees', 'equipment', 'knowledgebase',
CUTOVER_PLUGINS = ('computers', 'employees', 'knowledgebase', 'machines',
'network', 'notifications', 'printers', 'slides', 'usb', 'warranty')
@pytest.mark.parametrize('plugin', CUTOVER_PLUGINS) # not all plugins
@@ -281,7 +281,10 @@ def test_anchor_migration_is_noop(plugin):
```
Freezing the list (rather than deriving it) is intentional: a newly discovered
plugin should not silently be treated as a cutover no-op.
plugin should not silently be treated as a cutover no-op. Note that `machines`
(renamed from `equipment`, ADR-011) keeps its original cutover anchor but carries
a `machines0002rename` revision on top of it, so its expected head is that rename
revision rather than the bare anchor (`tests/test_plugin_migrations.py`).
---
@@ -499,23 +502,25 @@ the plugin small.
## 9. Frontend integration
There is no frontend plugin system yet (see
[ADR-009](adr/ADR-009-frontend-plugin-gating.md), "Future direction"). A plugin's
Vue routes and views ship in the core bundle. The plugin's job is to add them
correctly and gate them.
A plugin ships its own Vue routes and views under
`plugins/<name>/frontend/` (ADR-010's frontend plugin hook contract). At build
time those files are staged into `frontend/src/.plugins-staged/<name>/` so the
core bundle picks them up; you author them in the plugin tree, not in core
`frontend/src/`. The plugin's job is to add them correctly and gate them.
**Route module with `meta.plugin` gating (ADR-009).** A new file
`frontend/src/router/routes/measuringtools.js` is auto-discovered by the router's
**Route module with `meta.plugin` gating (ADR-009).** The file
`plugins/measuringtools/frontend/routes.js` is staged into
`frontend/src/.plugins-staged/measuringtools/` and auto-discovered by the router's
`import.meta.glob('./routes/*.js')`. Every route carries `meta.plugin =
'measuringtools'`:
```js
export default [
{ path: 'measuringtools', name: 'measuringtools',
component: () => import('../../views/measuringtools/MeasuringToolsList.vue'),
component: () => import('./views/MeasuringToolsList.vue'),
meta: { plugin: 'measuringtools' } },
{ path: 'measuringtools/new', name: 'measuringtool-new',
component: () => import('../../views/measuringtools/MeasuringToolForm.vue'),
component: () => import('./views/MeasuringToolForm.vue'),
meta: { requiresAuth: true, plugin: 'measuringtools' } },
{ path: 'measuringtools/:id', ..., meta: { plugin: 'measuringtools' } },
{ path: 'measuringtools/:id/edit', ..., meta: { requiresAuth: true, plugin: 'measuringtools' } },
@@ -539,18 +544,18 @@ reorganize the file; just add the block, mirroring `machinesApi`.
**Views mirror the master templates.** The frontend has master templates
(`PrintersList.vue` for lists, `PrinterDetail.vue` for detail pages). `measuringtools` mirrors the equivalent equipment views:
- `views/measuringtools/MeasuringToolsList.vue` - table with search, a type filter,
- `plugins/measuringtools/frontend/views/MeasuringToolsList.vue` - table with search, a type filter,
and a calibration-status filter; the status badge uses `utils/colorStyle` with
the color the API derived.
- `views/measuringtools/MeasuringToolDetail.vue` - hero + Identity card +
- `plugins/measuringtools/frontend/views/MeasuringToolDetail.vue` - hero + Identity card +
Calibration card (with the derived badge) + Location card, plus the shared
`CustomFieldsSection` and `WarrantyPanel` (section 10).
- `views/measuringtools/MeasuringToolForm.vue` - asset core fields + type +
- `plugins/measuringtools/frontend/views/MeasuringToolForm.vue` - asset core fields + type +
location + the calibration fields, plus `CustomFieldsInputs`.
- `views/reports/CalibrationReport.vue` - the four buckets (overdue / due soon /
- `plugins/measuringtools/frontend/views/CalibrationReport.vue` - the four buckets (overdue / due soon /
current / unknown), mirroring `WarrantyReport.vue`.
**Settings subtype page.** `views/settings/MeasuringToolTypesList.vue` mirrors
**Settings subtype page.** `plugins/measuringtools/frontend/views/MeasuringToolTypesList.vue` mirrors
`PCTypesList.vue`: add / edit / delete with a `ColorSwatchPicker`. It is linked from
`settingsNav.js` with a "Measuring Tools" card group, so it appears in the settings
rail and landing overview.
@@ -578,7 +583,7 @@ detail page drops in `<CustomFieldsSection :assetid="tool.assetid" />` and the f
drops in `<CustomFieldsInputs :assettypeid="assettypeid" :assetid="currentAssetId" />`,
then calls `customFieldsRef.value.save(assetId)` after the tool saves. The one
subtlety: `CustomFieldsInputs` needs the asset-type id. Rather than hardcode it (the
equipment form hardcodes `EQUIPMENT_ASSETTYPEID = 1`), the measuringtools form
machines form hardcodes `MACHINE_ASSETTYPEID = 1`), the measuringtools form
resolves it dynamically from `GET /api/assets/types`, finding the row whose
`assettype === 'measuring_tool'`. Dynamic lookup is preferred because seeded ids are
not stable across sites.