fix(skills): align repository guidance with implementation (#1315)

* docs(skills): design implementation synchronization

* docs(skills): plan implementation synchronization

* fix(release): filter internal notes from public body

* docs(release): synchronize release workflow guidance

* fix(stalker): normalize catalog series flags

* fix(stalker): preserve progress with scoped episode IDs

* fix(playback): expose strict position persistence

* docs(stalker): record series position compatibility

* test(skills): validate repository skill contracts

* fix(database): keep SQL trace values private

* docs(skills): refresh Nx and SQLite ownership

* docs(skills): align provider and UI guidance

* docs(skills): tighten validated guidance

* docs(release): require exact release pushes

* style(electron): remove trailing blank line

* fix(ci): classify repository skills coverage
This commit is contained in:
4gray authored and GitHub committed 2026-07-31 08:00:59 +02:00
1 parent 99d167993d
commit 2ac0de752f
68 files changed
+7524 -793

No files matched your search

@@ -321,4 +321,3 @@ type ActiveXtreamRequest = {
};
const activeXtreamRequests = new Map<string, ActiveXtreamRequest>();
@@ -1,4 +1,4 @@
import { trace } from './debug-trace';
import { trace, traceSqlStatement } from './debug-trace';
describe('debug trace redaction', () => {
afterEach(() => {
@@ -44,4 +44,25 @@ describe('debug trace redaction', () => {
expect(output).toContain('[Redacted]');
expect(output).toContain('get_profile');
});
it('records only the statement type for expanded worker SQL', () => {
jest.spyOn(console, 'log').mockImplementation(() => undefined);
const secrets = [
'worker-user-secret',
'worker-password-secret',
'https://worker-user:worker-password@example.com/live?token=worker-token-secret',
];
traceSqlStatement(
'sql-worker',
`INSERT INTO playlists (username, password, url) VALUES ('${secrets[0]}', '${secrets[1]}', '${secrets[2]}')`
);
const output = (console.log as jest.Mock).mock.calls.flat().join('\n');
expect(output).toContain('"statementType":"INSERT"');
expect(output).not.toContain('INSERT INTO');
for (const secret of secrets) {
expect(output).not.toContain(secret);
}
});
});
@@ -1,4 +1,7 @@
import { redactSensitiveData } from '@iptvnator/shared/logging';
import {
redactSensitiveData,
summarizeSqlStatementForTrace,
} from '@iptvnator/shared/logging';
const TRACE_ENV_TRUE_VALUES = new Set(['1', 'true', 'yes', 'on']);
const TRACE_PREFIX = '[IPTVnator Trace]';
@@ -84,10 +87,6 @@ export function roundTraceDuration(durationMs: number): number {
return Math.round(durationMs * 10) / 10;
}
export function compactSqlForTrace(sql: string): string {
return truncateString(sql.replace(/\s+/g, ' ').trim());
}
export function summarizeForTrace(value: unknown, depth = 0): unknown {
if (
value == null ||
@@ -176,3 +175,7 @@ export function trace(scope: string, message: string, payload?: unknown): void {
)}`
);
}
export function traceSqlStatement(scope: string, sql: unknown): void {
trace(scope, 'query', summarizeSqlStatementForTrace(sql));
}
@@ -10,9 +10,9 @@ import {
registerNativeModuleSearchPaths,
} from './worker-runtime-paths';
import {
compactSqlForTrace,
isSqlTraceEnabled,
trace,
traceSqlStatement,
} from '../services/debug-trace';
let drizzleFactory:
@@ -67,11 +67,7 @@ export async function getWorkerDatabase(): Promise<AppDatabase> {
const filePath = getIptvnatorDatabasePath();
sqlite = new Database(filePath, {
verbose: isSqlTraceEnabled()
? (sql: string) => {
trace('sql-worker', 'query', {
sql: compactSqlForTrace(sql),
});
}
? (sql: string) => traceSqlStatement('sql-worker', sql)
: undefined,
});
sqlite.pragma('foreign_keys = ON');