8.4 KiB
ShopDB Flask - Project Health Review
As of HEAD ecf4ef6 (2026-07-30), product __version__ 0.7.0, contract __contract_version__ 0.15.0 (verified in shopdb/__init__.py).
1. Executive Summary
Overall: healthy engineering, drifting focus. The stated product vision ("plugin system is the product," CLAUDE.md) is delivered: all 7 refactor phases are done, 13 bundled plugins are contract-compliant, the per-plugin migration regime (ADR-008) is live and exercised (geenforce is at geenforce0002blobs, proving the post-cutover chain works in anger), and CI enforces naming, contract, and real-MySQL migration idempotency. Test count grew 1077 -> 1159 since the last CLAUDE.md snapshot.
The concern is not quality but trajectory. CLAUDE.md and ROADMAP.md both name the last big milestone before 1.0 as "legacy-ASP data import + production pilot." The loader is built and VM-validated (16 stages, scripts/site_imports/wjf/), but the prod run has not happened, and ~35 of the last 60 commits went to the GE-Enforce HTTPS cutover instead. That work is legitimate and high-value, but it is feature/fleet work on one plugin, and it has accumulated two process debts that violate the project's own discipline: the cutover playbook (docs/geenforce-api-cutover.md) is the only dirty file in the repo and is untracked, and the prod-patch-geenforce robocopy fast-path can leave prod ahead of git.
Verdict: on track against standards, behind against goals. The 1.0 gate has four items; only one is arguably done, and the roadmap doc does not know it.
2. Standards Compliance
| Rule | Status | Evidence |
|---|---|---|
| Naming (tables/columns/vars, CONTRIBUTING.md) | MET | scripts/check-naming-and-style.sh present and executable; dedicated naming job in .gitea/workflows/ci.yml. One borderline: asset.py:175 documents a derived API key location_name with an underscore - not a DB-mirrored column so likely legal, but worth a glance since "response keys match column names exactly" is the spirit of the rule. |
Plugin contract (manifest.json, BasePlugin, shopdb.api only) |
MET | 13 plugins/*/manifest.json verified; contract test suites in tests/; contract bumped correctly to 0.15.0 for the geenforce resource-scope fetch tokens (75386d2), per ADR-002 discipline. |
| Migration ownership (ADR-008) | MET | PLUGIN_TABLE_OWNERS registry tested by tests/test_plugin_migrations.py (EXPECTED_HEAD_REVISION lines 47-51); migrations-mysql CI job does fresh utf8mb4 MySQL 8 upgrade + all plugin chains + second-upgrade-no-op assertion. The geenforce 0002blobs revision shows the per-plugin chain is being used as designed, not just anchored. |
| Versioning/release discipline (ADR-007) | AT RISK | Tags through v0.7.0 exist and contract bumps are disciplined, but the documentation half of the procedure has drifted - see Gaps 3. |
| ADRs canonical, new priorities get an ADR | AT RISK | 14 ADRs present. But lean per-site builds are half-shipped (ADR-014 ACCEPTED and implemented; default_enabled: false on 5 plugins) while ADR-013, which defines the catalog/tiers/signed-artifact model those builds imply, is still PROPOSED. The GE-Enforce HTTPS cutover itself - a major architectural shift off the SMB share - lives in an untracked doc, not an ADR or ADR-012 amendment. |
| Style (plain ASCII, no emojis, comment discipline) | MET | Enforced by the same pre-commit hook + CI naming job. |
| Everything in git / repo as source of truth | VIOLATED | docs/geenforce-api-cutover.md untracked (only dirty file, verified git status); prod-patch-geenforce robocopy path acknowledged in-doc as leaving prod ahead of git. |
3. Roadmap Status
Done: Phases 0-6 (contract lock through multi-site distribution, tags v0.5.0-v0.7.0). Legacy import machinery complete: docs/IMPORT-API.md contract, 16-stage wjf loader VM-validated. Air-gapped deploy kit (6534590).
1.0 must-haves (ROADMAP.md), honestly scored:
- Asset model fully wired - appears DONE but unrecorded.
Asset.mapx(shopdb/core/models/asset.py:121),inheritsposition(relationship.py:132), and propagation logic (relationship.py,core/api/assets.py,cli/__init__.py) are all in code. ROADMAP still lists this as outstanding. Verify the ADR-001 contract tests cover it, then strike it. - Equipment data migration one-shot - NOT DONE.
scripts/migration/contains onlyfix_legacy_schema.sql,one-offs/, and a README. No equipment script. - Printers legacy-table cleanup - NOT DONE. Recent printers commits (0d40780..c075658) are installer/feature work, not retirement.
- External plugin UI packaging - NOT DONE, and gate criterion 3 (one external plugin built end-to-end) has no evidence.
In-flight: GE-Enforce HTTPS cutover dominates (~35/60 recent commits). Per the cutover doc's own section 12: only displays/kiosks are on the API; cmm/collections/keyence/genspect/heattreat/partmarker/common fleet still enforce from the SFLD SMB share; loggedinuser resolution unwired; registry cleanup pending; 3DPrintRoom route is a placeholder. Secondary streams: printers install-batch, applications notes, server reclassification, TV dashboard.
Pace/scope health: Velocity is high and test coverage tracks the work (17 of ~29 plugin test files are geenforce). But the project has been at 0.7.0 with "prod pilot is the last big milestone" as the stated goal since mid-July, while shipping ~185 commits of plugin-feature work. That is a real product being used - good - but the 1.0 gate is not moving, and a half-migrated fleet (API for displays, SMB for everything else) is the worst place to pause the cutover.
4. Gaps and Risks
- Untracked cutover playbook (
docs/geenforce-api-cutover.md). The single most valuable in-flight document is onermaway from gone, and invisible to any other machine or contributor. - Prod-ahead-of-git debt. The
prod-patch-geenforcefast-path means production behavior may not be reproducible from any commit. This directly undermines ADR-012's "engine is source of truth" and the release discipline of ADR-007. - Documentation drift, three concrete instances (all verified): ROADMAP.md header says contract 0.13.0 (actual 0.15.0); CLAUDE.md says 1077 tests (actual 1159 collected) and claims a "lean-build" CI job that does not exist in
.gitea/workflows/ci.yml(jobs: backend, naming, frontend, migrations-mysql - lean coverage is folded into pytest viatests/test_lean_build_guards.py). Also.github/workflows/ci.ymldiffers from the gitea workflow - one of them is stale. - Split-brain fleet enforcement. Displays/kiosks on the API, the rest of the fleet on the SMB share, with staged-but-unpushed manifest fixes elsewhere (MTConnect v1 stranding). Two delivery mechanisms means two failure modes and doubles the audit surface until the cutover finishes.
- 1.0 gate criterion 4 unproven:
docs/DEPLOY.mdhas not been validated by an actual fresh-host prod deploy. The air-gapped kit exists; the pilot does not. - ADR-013 limbo: lean builds shipped under ADR-014 while the catalog/signing model that makes external distribution safe remains PROPOSED. Fine short-term, but gate criterion 3 (external plugin) will force the question.
5. Prioritized Recommendations
- Commit
docs/geenforce-api-cutover.mdtoday. Zero-cost, eliminates the worst single-point-of-loss risk. - Reconcile prod-patched geenforce files back into git and gate or retire the robocopy fast-path. Until prod == some tag, ADR-007 is fiction for this plugin.
- One doc-sync pass (30 min): ROADMAP header to 0.15.0, CLAUDE.md test count and CI job list, strike must-have (a) if contract tests confirm the Asset wiring, delete or sync the stale
.githubworkflow. - Finish the cutover or park it cleanly. Either drive the remaining fleet groups onto the API per section 12, or write down the frozen state as an ADR-012 amendment so the split-brain period is a documented decision, not drift.
- Schedule the prodscratch import run and prod pilot. This is the actual 1.0 milestone and everything is built for it; it validates DEPLOY.md (gate 4) for free.
- Pair the equipment one-shot migration with printers retirement (must-haves b and c) - they are coordinated by design; doing them together avoids touching the legacy tables twice.
- Decide ADR-013 before building the external-plugin end-to-end proof (gate 3); the geenforce client work is the natural seed for that external plugin.