Skip to content

Commit 0fedc1d

Browse files
committed
fix(cmc/formSpec): rename FORM_SPEC_EVENT_TYPE to hds-form-spec/v1 (slash separator)
Pryv's events.get `types` filter rejects values that don't match `^(series:)?[a-z0-9-]+/(\*|[a-z0-9-]+)$` with `invalid-parameters-format`. The previous value `'hds:form-spec-v1'` (colon separator) silently passed events.create but failed every events.get + loadFormSpec call. Never observed before because no consumer of saveFormSpec / loadFormSpec existed in production — discovered when plan 61 C1.a (FormBuilder write port) made these the first live callers. No data migration needed. Updates `[CFS01]` + `[CFS40]` assertions. 546/546 tests pass.
1 parent 7b468ac commit 0fedc1d

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

tests/cmcFormSpec.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ describe('[CFSP] cmcFormSpec helpers', function () {
2424
}
2525

2626
describe('[CFSC] constants', function () {
27-
it('[CFS01] FORM_SPEC_EVENT_TYPE matches the locked Q-F5 name', () => {
28-
assert.equal(cmcFormSpec.FORM_SPEC_EVENT_TYPE, 'hds:form-spec-v1');
27+
it('[CFS01] FORM_SPEC_EVENT_TYPE is `hds-form-spec/v1` (slash-form per Pryv events.get regex)', () => {
28+
assert.equal(cmcFormSpec.FORM_SPEC_EVENT_TYPE, 'hds-form-spec/v1');
2929
});
3030

3131
it('[CFS02] HDS_NOOP_STREAM_ID + permission match the brief', () => {
@@ -124,13 +124,13 @@ describe('[CFSP] cmcFormSpec helpers', function () {
124124
return { conn, calls };
125125
}
126126

127-
it('[CFS40] queries the :_cmc:apps:hds-collector parent stream filtered to hds:form-spec-v1', async () => {
127+
it('[CFS40] queries the :_cmc:apps:hds-collector parent stream filtered to hds-form-spec/v1', async () => {
128128
const { conn, calls } = fakeConnection([]);
129129
await cmcFormSpec.listFormSpecs(conn);
130130
assert.equal(calls.length, 1);
131131
assert.equal(calls[0].method, 'events.get');
132132
assert.deepEqual(calls[0].params.streams, [':_cmc:apps:hds-collector']);
133-
assert.deepEqual(calls[0].params.types, ['hds:form-spec-v1']);
133+
assert.deepEqual(calls[0].params.types, ['hds-form-spec/v1']);
134134
assert.equal(calls[0].params.limit, 1000);
135135
assert.equal(calls[0].resultKey, 'events');
136136
});

ts/cmc/formSpec.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* derive the CMC `requestedPermissions` and is mirrored as a snapshot
88
* onto the per-invite trigger event content (Q-F6 lock: snapshot-frozen).
99
*
10-
* Storage (Q-F5 lock: hds:form-spec-v1):
10+
* Storage (Q-F5 lock: hds-form-spec/v1 — slash separator required by Pryv events.get types regex):
1111
* - **Doctor side**: one canonical template event per data-set, stored
1212
* on the doctor's `:_cmc:apps:hds-collector:<collectorId>` scope stream.
1313
* - **Per-invite snapshot**: doctor's `consent/request-cmc` trigger event
@@ -34,8 +34,19 @@ import type {
3434
ExistingStreamRef
3535
} from '../appTemplates/templateTypes.ts';
3636

37-
/** Event type for the canonical FormSpec template event on the doctor side. */
38-
export const FORM_SPEC_EVENT_TYPE = 'hds:form-spec-v1';
37+
/**
38+
* Event type for the canonical FormSpec template event on the doctor side.
39+
*
40+
* Must satisfy Pryv's events.get `types` filter regex
41+
* `^(series:)?[a-z0-9-]+/(\*|[a-z0-9-]+)$` — i.e. `<category>/<name>` with
42+
* `/` (not `:`) separator. Original Plan 59 Phase 5a value was
43+
* `'hds:form-spec-v1'` which `events.create` accepted silently but
44+
* `events.get` rejected with `invalid-parameters-format` when used in a
45+
* types filter; corrected to slash form in plan 61 C1.a verification
46+
* (Round 7, 2026-05-27). No production data was migrated — the only
47+
* consumer of saveFormSpec was added in C1.a itself.
48+
*/
49+
export const FORM_SPEC_EVENT_TYPE = 'hds-form-spec/v1';
3950

4051
/** The HDS no-op permission stream — see Q-F3/F4 in the FormSpec design brief. */
4152
export const HDS_NOOP_STREAM_ID = 'hds-noop';
@@ -133,15 +144,15 @@ export interface FormSpecRecord {
133144
collectorId: string;
134145
/** The FormSpec content as authored. */
135146
formSpec: FormSpec;
136-
/** The raw `hds:form-spec-v1` event (id, modified, etc.). */
147+
/** The raw `hds-form-spec/v1` event (id, modified, etc.). */
137148
event: pryv.Event;
138149
}
139150

140151
/**
141-
* Pure helper: lift a raw `hds:form-spec-v1` event onto its scope-stream
152+
* Pure helper: lift a raw `hds-form-spec/v1` event onto its scope-stream
142153
* `collectorId`. Exported for unit-testing in isolation from the I/O layer.
143154
*
144-
* @param event a `hds:form-spec-v1` event read from a `:_cmc:apps:<appCode>:*` stream.
155+
* @param event a `hds-form-spec/v1` event read from a `:_cmc:apps:<appCode>:*` stream.
145156
* @param appCode defaults to `CMC_APP_CODES.COLLECTOR`.
146157
*/
147158
export function eventToFormSpecRecord (

0 commit comments

Comments
 (0)