@adobe/spacecat-shared-data-access 4.7.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [@adobe/spacecat-shared-data-access-v4.9.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.8.0...@adobe/spacecat-shared-data-access-v4.9.0) (2026-07-15)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **data-access:** guidance + feedback_subject_id + code-patch export gate for feedback ([#1809](https://github.com/adobe/spacecat-shared/issues/1809)) ([941b9f9](https://github.com/adobe/spacecat-shared/commit/941b9f92621df09a9ce887b70307f4c1261bfd37))
|
|
6
|
+
|
|
7
|
+
## [@adobe/spacecat-shared-data-access-v4.8.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.7.0...@adobe/spacecat-shared-data-access-v4.8.0) (2026-07-14)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* add temporary replaceHandlerEnabledDisabled method for cleanup. ([#1328](https://github.com/adobe/spacecat-shared/issues/1328)) ([be9234f](https://github.com/adobe/spacecat-shared/commit/be9234fa67dc9960d4abbb0b0425e621b7ad33c7))
|
|
12
|
+
|
|
1
13
|
## [@adobe/spacecat-shared-data-access-v4.7.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.6.0...@adobe/spacecat-shared-data-access-v4.7.0) (2026-07-13)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/package.json
CHANGED
|
@@ -554,6 +554,84 @@ class Configuration {
|
|
|
554
554
|
this.setHandlers(handlers);
|
|
555
555
|
}
|
|
556
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Replaces enabled/disabled lists for a handler.
|
|
559
|
+
* This method replaces (not merges) the provided arrays.
|
|
560
|
+
* Only the arrays provided in the data object will be replaced.
|
|
561
|
+
*
|
|
562
|
+
* TEMPORARY: This method was created to support a temporary API endpoint for
|
|
563
|
+
* cleaning up enabled and disabled lists (SITES-40312). It will be removed once the cleanup
|
|
564
|
+
* task is completed. SITES-40878 is the ticket to remove this temporary endpoint.
|
|
565
|
+
*
|
|
566
|
+
* @deprecated Temporary method for cleanup. See SITES-40312. Will be removed (SITES-40878).
|
|
567
|
+
* @param {string} type - The handler type to update
|
|
568
|
+
* @param {object} data - Object containing enabled/disabled arrays to replace
|
|
569
|
+
* @param {object} [data.enabled] - Enabled lists to replace (use null-safe check)
|
|
570
|
+
* @param {string[]} [data.enabled.sites] - Sites array to replace (if provided, must be array)
|
|
571
|
+
* @param {string[]} [data.enabled.orgs] - Orgs array to replace (if provided, must be array)
|
|
572
|
+
* @param {object} [data.disabled] - Disabled lists to replace (use null-safe check)
|
|
573
|
+
* @param {string[]} [data.disabled.sites] - Sites array to replace (if provided, must be array)
|
|
574
|
+
* @param {string[]} [data.disabled.orgs] - Orgs array to replace (if provided, must be array)
|
|
575
|
+
* @throws {Error} If data is empty, handler not found, or non-array value provided for sites/orgs
|
|
576
|
+
*/
|
|
577
|
+
replaceHandlerEnabledDisabled(type, data) {
|
|
578
|
+
if (!isNonEmptyObject(data)) {
|
|
579
|
+
throw new Error('Data cannot be empty');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
this.log.warn('replaceHandlerEnabledDisabled invoked (temporary method - see SITES-40312)');
|
|
583
|
+
|
|
584
|
+
const handlers = this.getHandlers();
|
|
585
|
+
if (!handlers[type]) {
|
|
586
|
+
throw new Error(`Handler "${type}" not found in configuration`);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const handler = handlers[type];
|
|
590
|
+
|
|
591
|
+
// Initialize enabled/disabled objects if they don't exist
|
|
592
|
+
if (!isNonEmptyObject(handler.enabled)) {
|
|
593
|
+
handler.enabled = { orgs: [], sites: [] };
|
|
594
|
+
}
|
|
595
|
+
if (!isNonEmptyObject(handler.disabled)) {
|
|
596
|
+
handler.disabled = { orgs: [], sites: [] };
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Replace enabled arrays if provided (use != null to catch both null and undefined)
|
|
600
|
+
if (data.enabled != null) {
|
|
601
|
+
if (data.enabled.sites !== undefined) {
|
|
602
|
+
if (!Array.isArray(data.enabled.sites)) {
|
|
603
|
+
throw new Error('enabled.sites must be an array');
|
|
604
|
+
}
|
|
605
|
+
handler.enabled.sites = data.enabled.sites;
|
|
606
|
+
}
|
|
607
|
+
if (data.enabled.orgs !== undefined) {
|
|
608
|
+
if (!Array.isArray(data.enabled.orgs)) {
|
|
609
|
+
throw new Error('enabled.orgs must be an array');
|
|
610
|
+
}
|
|
611
|
+
handler.enabled.orgs = data.enabled.orgs;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Replace disabled arrays if provided (use != null to catch both null and undefined)
|
|
616
|
+
if (data.disabled != null) {
|
|
617
|
+
if (data.disabled.sites !== undefined) {
|
|
618
|
+
if (!Array.isArray(data.disabled.sites)) {
|
|
619
|
+
throw new Error('disabled.sites must be an array');
|
|
620
|
+
}
|
|
621
|
+
handler.disabled.sites = data.disabled.sites;
|
|
622
|
+
}
|
|
623
|
+
if (data.disabled.orgs !== undefined) {
|
|
624
|
+
if (!Array.isArray(data.disabled.orgs)) {
|
|
625
|
+
throw new Error('disabled.orgs must be an array');
|
|
626
|
+
}
|
|
627
|
+
handler.disabled.orgs = data.disabled.orgs;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
handlers[type] = handler;
|
|
632
|
+
this.setHandlers(handlers);
|
|
633
|
+
}
|
|
634
|
+
|
|
557
635
|
/**
|
|
558
636
|
* Updates the configuration by merging changes into existing sections.
|
|
559
637
|
* This is a flexible update method that allows updating one or more sections at once.
|
|
@@ -40,6 +40,10 @@ export interface Configuration {
|
|
|
40
40
|
isHandlerEnabledForOrg(type: string, org: Organization): boolean;
|
|
41
41
|
isHandlerEnabledForSite(type: string, site: Site): boolean;
|
|
42
42
|
registerAudit(type: string, enabledByDefault?: boolean, interval?: string, productCodes?: string[]): void;
|
|
43
|
+
replaceHandlerEnabledDisabled(
|
|
44
|
+
type: string,
|
|
45
|
+
data: { enabled?: { sites?: string[]; orgs?: string[] }; disabled?: { sites?: string[]; orgs?: string[] } }
|
|
46
|
+
): void;
|
|
43
47
|
save(): Promise<Configuration>;
|
|
44
48
|
setHandlers(handlers: object): void;
|
|
45
49
|
setJobs(jobs: object[]): void;
|
|
@@ -79,16 +79,19 @@ export const EXPORT_EXCLUDED_REJECTION_CATEGORIES = Object.freeze([
|
|
|
79
79
|
]);
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
* `training_opt_in = false
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
82
|
+
* HUMAN-authored fields stripped from the JSONL export for organizations with
|
|
83
|
+
* `training_opt_in = false`: the reviewer's written feedback (`detail_markdown`)
|
|
84
|
+
* and their hand-corrected patch (`edited_fix`). The AI-generated fields — the
|
|
85
|
+
* issue context (`guidance_markdown`) and the generated patch (`previous_fix`) —
|
|
86
|
+
* are ALWAYS exported (the Learning Agent needs the issue + generated patch to
|
|
87
|
+
* map a verdict to what was generated), as are verdict / signal / category /
|
|
88
|
+
* identity metadata. snake_case to match the JSONL row shape (and the
|
|
89
|
+
* feedback_event DB columns) — {@link toJsonlRow} uses this list to do the
|
|
90
|
+
* stripping, so the opt-out boundary is single-sourced here (SITES-43974).
|
|
87
91
|
*/
|
|
88
92
|
export const OPT_OUT_STRIPPED_FIELDS = Object.freeze([
|
|
89
|
-
'previous_fix',
|
|
90
|
-
'edited_fix',
|
|
91
93
|
'detail_markdown',
|
|
94
|
+
'edited_fix',
|
|
92
95
|
]);
|
|
93
96
|
|
|
94
97
|
/**
|
|
@@ -163,11 +166,17 @@ export function toReviewView(row, { includePatches = false } = {}) {
|
|
|
163
166
|
rejectionCategory: row.rejection_category ?? null,
|
|
164
167
|
stateTransition: row.state_transition ?? null,
|
|
165
168
|
tier: row.tier,
|
|
169
|
+
// Sub-item id (e.g. a CWV issue) this review is about; the Backoffice groups
|
|
170
|
+
// its per-issue "previous feedback" table on it. Always in the base view (the
|
|
171
|
+
// UI filters on it) — not gated behind includePatches. Null for
|
|
172
|
+
// whole-suggestion reviews.
|
|
173
|
+
feedbackSubjectId: row.feedback_subject_id ?? null,
|
|
166
174
|
};
|
|
167
175
|
|
|
168
176
|
if (includePatches) {
|
|
169
177
|
view.previousFix = row.previous_fix ?? null;
|
|
170
178
|
view.editedFix = row.edited_fix ?? null;
|
|
179
|
+
view.guidanceMarkdown = row.guidance_markdown ?? null;
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
return view;
|
|
@@ -175,14 +184,21 @@ export function toReviewView(row, { includePatches = false } = {}) {
|
|
|
175
184
|
|
|
176
185
|
/**
|
|
177
186
|
* Whether a raw `feedback_event` row should be exported to the Learning Agent
|
|
178
|
-
* corpus.
|
|
179
|
-
*
|
|
187
|
+
* corpus. Two gates (SITES-43974):
|
|
188
|
+
* 1. It must carry a generated code patch (`previous_fix`). The corpus is
|
|
189
|
+
* code-patch feedback; text-guidance-only reviews (no patch) are retained
|
|
190
|
+
* in Postgres but NOT exported — reserved for a future text-guidance corpus.
|
|
191
|
+
* 2. `product_bug` rejections are excluded (routed to Jira). NULL-category rows
|
|
192
|
+
* (approvals / uncategorised) ARE exported. See
|
|
193
|
+
* {@link EXPORT_EXCLUDED_REJECTION_CATEGORIES}.
|
|
180
194
|
*
|
|
181
195
|
* @param {object} row - a raw feedback_event row from PostgREST.
|
|
182
196
|
* @returns {boolean} true if the row should be exported.
|
|
183
197
|
*/
|
|
184
198
|
export function shouldExport(row) {
|
|
185
|
-
|
|
199
|
+
const hasCodePatch = row.previous_fix != null;
|
|
200
|
+
return hasCodePatch
|
|
201
|
+
&& !EXPORT_EXCLUDED_REJECTION_CATEGORIES.includes(row.rejection_category);
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
/**
|
|
@@ -190,8 +206,10 @@ export function shouldExport(row) {
|
|
|
190
206
|
* object — the canonical Learning Agent export contract. The row mirrors the
|
|
191
207
|
* feedback_event columns (snake_case), stamped with {@link SCHEMA_VERSION} and
|
|
192
208
|
* the derived `verdict`. For organizations that have NOT opted into training,
|
|
193
|
-
* the
|
|
194
|
-
*
|
|
209
|
+
* the HUMAN-authored fields in {@link OPT_OUT_STRIPPED_FIELDS} are nulled; the
|
|
210
|
+
* AI-generated issue context (`guidance_markdown`) + generated patch
|
|
211
|
+
* (`previous_fix`) and the verdict / signal / category / identity metadata still
|
|
212
|
+
* ship (§10.5.7).
|
|
195
213
|
*
|
|
196
214
|
* This is the single source of truth for the JSONL row shape — the exporter
|
|
197
215
|
* (spacecat-jobs-dispatcher) calls it rather than re-deriving the contract.
|
|
@@ -218,6 +236,7 @@ export function toJsonlRow(row, { optedIn = false } = {}) {
|
|
|
218
236
|
state_transition: row.state_transition ?? null,
|
|
219
237
|
tier: row.tier,
|
|
220
238
|
detail_markdown: row.detail_markdown ?? null,
|
|
239
|
+
guidance_markdown: row.guidance_markdown ?? null,
|
|
221
240
|
previous_fix: row.previous_fix ?? null,
|
|
222
241
|
edited_fix: row.edited_fix ?? null,
|
|
223
242
|
};
|
|
@@ -53,8 +53,10 @@ export interface ReviewView {
|
|
|
53
53
|
rejectionCategory: string | null;
|
|
54
54
|
stateTransition: string | null;
|
|
55
55
|
tier: string;
|
|
56
|
+
feedbackSubjectId: string | null;
|
|
56
57
|
previousFix?: unknown;
|
|
57
58
|
editedFix?: unknown;
|
|
59
|
+
guidanceMarkdown?: string | null;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
/**
|