fix(offline): planned inspections carried no checklist template ref — found by a real gate-24 parity check - #743
Conversation
…gate-24 parity check
procest registers the `field-inspection` OpenRegister leaf in `src/main.js`,
overriding the nc-vue builtin with its own `offlineConfig`, but shipped no
`scripts/check-integration-parity.sh`, so hydra gate-24 reported:
[gate-24] integration-parity: SKIPPED (structural) — ... server↔JS leaf
parity (ADR-066 Decisions 4/7 ...) is UNVERIFIED
Writing the check found a REAL defect on its first run.
THE DEFECT. `offlineConfig.templateRefField` is 'checklistTemplateRef', and
nc-vue's CnFieldInspectionCard reads it off the PLANNED item:
const templateRef = item?.[cfg.templateRefField]
this.activeTemplate = templateRef ? await getCachedObject(...) : null
The planned item is a `fieldInspection`, and this repo's `fieldInspection`
schema declared no `checklistTemplateRef` property — only `checklistResult` had
one. So `templateRef` was always undefined, `activeTemplate` always null, and
`answers` always `{}`: an inspector opening a planned inspection offline got an
EMPTY checklist, every time, with no error anywhere. The registration and the
schema had drifted and nothing correlated them. (`src/main.js` says the mapping
"mirrors DailySyncService exactly" — no such class exists in this repo; the
mapping was written against the design doc, where checklistTemplateRef sits on
the RESULT.)
THE FIX. Declare `checklistTemplateRef` on the `fieldInspection` schema — the
template the inspector must complete for that inspection, read off the planned
item by the leaf and copied onto the resulting `checklistResult`. Additive and
optional (not added to `required`), so existing objects stay valid.
THE CHECK. Self-contained on purpose: the canonical Node check in
@conduction/nextcloud-vue validates that library's own built-ins, its ADR-066
cross-reference is WARN-only and self-disables in a repo with no
`new LeafDescriptor(` (procest has none — its leaf is a builtin override, so it
would have stayed silent here), and its `scripts/` dir is not published to npm.
Every way this one can fail to check exits non-zero with a named reason.
Rules, all hard (ADR-019 AD-11/AD-13, ADR-066 decisions 4 and 7):
R1 complete render pair for the declared renderMode (mount+unmount / tab+widget)
R2 server↔JS id correlation, both ways (phantom leaf / orphan registration)
R3 renderMode agreement across layers under a shared id
R4 metadata agreement (label, icon, group, requiredApp, referenceType, surfaces)
R5 a spread-inherited identity must come from the leaf-owning package
R6 an offlineConfig must name schemas/properties this repo actually declares
procest exercises R5 (1) and R6 (7) — the counts are printed, so "verified" and
"nothing to verify" are distinguishable in the log. A run where every rule has
zero subject matter fails rather than passes.
Positive control (proved it can fail, then restored):
* the defect itself — before the schema fix the check exited 1 with
"[R6 offlineConfig] leaf offlineConfig.templateRefField =
"checklistTemplateRef" ... is not a property of schema "fieldInspection""
* titleField drift — 'caseRef' -> 'caseReference' => exit 1, R6 names it
* spread drift — `...fieldInspectionIntegration` -> an unimported binding
=> exit 1, "[R5 spread-source] ... the spread of an undefined binding
registers a leaf with no id"
All restored; the check passes on the fixed tree.
Quality Report — ConductionNL/procest @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 550/550 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-05 19:10 UTC
Download the full PDF report from the workflow artifacts.
Status: gate-24 is fixed and PASSing. This PR is blocked by unrelated pre-existing debt.Hydra Gates on this PR: 1 gate failed, and it is not this one. gate-24 went from Why gate-53 firesAll 9 blocking findings are in They are pre-existing, and measurably independent of this diff. Running gate-53's own helper over this tree with the schema change reverted yields the identical finding count: They block only because of how gate-53 scopes itself. From if "register" in rel and rel.endswith(".json") and rel.startswith("lib/"):
# A register edit can invalidate a register/schema slug referenced
# from ANY page. There is no per-page answer to be had.
print("ALL")so any edit to any The consequence is bigger than this PR: procest currently cannot accept ANY register/schema edit until those 9 are resolved. The decision needed (not mine to take)
ADR-044's removals invariant says a removal must not leave a route no surviving menu entry reaches. procest's navigation design says exactly that is deliberate. Resolving it means one of:
Each is a product decision about nine live features. I am not taking it unilaterally, and I have not added a waiver, a baseline, a Tracked as #744. What is NOT in questionThe defect this PR fixes is real and independent of all of the above: |
Verified and merged — the red
|
The defect this found
procest overrides the nc-vue
field-inspectionleaf insrc/main.jswith its ownofflineConfig, but shipped noscripts/check-integration-parity.sh, so hydra gate-24 said, at the v1.3.0 pin:Writing the check found a real defect on its first run.
offlineConfig.templateRefFieldis'checklistTemplateRef', and nc-vue'sCnFieldInspectionCardreads it off the planned item:The planned item is a
fieldInspection, and this repo'sfieldInspectionschema declared nochecklistTemplateRefproperty — onlychecklistResulthad one. SotemplateRefwas alwaysundefined,activeTemplatealwaysnull, andanswersalways{}:The registration and the schema had drifted and nothing correlated them.
src/main.jssays the mapping "mirrorsDailySyncServiceexactly" — there is no such class in this repo; the mapping was written against the design doc, wherechecklistTemplateRefsits on the result, not on the inspection.The fix
Declare
checklistTemplateRefon thefieldInspectionschema — the template the inspector must complete for that inspection, read off the planned item by the leaf and copied onto the resultingchecklistResult. Additive and optional (not added torequired), so existing objects stay valid.The check
Self-contained on purpose. The canonical Node check in
@conduction/nextcloud-vuevalidates that library's built-ins, its ADR-066 cross-reference is WARN-only and self-disables in a repo with nonew LeafDescriptor((procest has none — its leaf is a builtin override, so it would have stayed silent here), and itsscripts/dir is not published to npm, so the historic wrapper shape resolves nothing in CI and exits 0 having checked nothing. Every way this one can fail to check exits non-zero with a named reason.mount+unmount/tab+widget)label,icon,group,requiredApp,referenceType,surfacesofflineConfigmust name schemas/properties this repo actually declaresOutput after the fix:
The per-rule counts are printed so "verified" and "there was nothing to verify" are distinguishable. A run where every rule has zero subject matter exits 1.
Positive control — it has been seen to FAIL
[R6 offlineConfig] leaf offlineConfig.templateRefField = "checklistTemplateRef" … is not a property of schema "fieldInspection"titleField'caseRef'→'caseReference'...fieldInspectionIntegration→ an unimported binding[R5 spread-source] … the spread of an undefined binding registers a leaf with no idAll restored; the check passes on the fixed tree.
gate-24, measured with the v1.3.0 script
[gate-24] integration-parity: SKIPPED (structural) — … is UNVERIFIED[gate-24] integration-parity: PASSIt passes because the checker ran and returned 0 — the gate only reaches
_pass 24insideif [ -f scripts/check-integration-parity.sh ], after executing it.