From 27ec203dd24e94fc4c5c8f7b347fbac0d64f0f5c Mon Sep 17 00:00:00 2001 From: Thomas Jung Date: Tue, 25 Aug 2026 17:31:22 -0400 Subject: [PATCH 1/2] =?UTF-8?q?Release=201.19.0=20=E2=86=92=20PROD=20(Opti?= =?UTF-8?q?on=20B=20content=20migration=20+=20bundled=20features)=20(#2038?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * freshness: give the LLM tutorial context + SAP-aware rules The freshness scan judged code blocks in isolation and applied generic best-practice dogma, producing false positives (intentional errors, demo base64 credentials, dev-container setup, npm version-pinning advice that contradicts CAP guidance). - extractCodeBlocks now captures contextBefore/contextAfter (the prose paragraph adjacent to each fence). - extractTutorialContext pulls frontmatter + Prerequisites, fed once at the top of the prompt so the model knows the reader's environment. - SYSTEM_PROMPT now instructs the model to judge blocks in context, respect intentional teaching artifacts (deliberate errors, illustrative demo credentials), and follow SAP/CAP conventions (never suggest pinning @sap/* package versions). - Export SYSTEM_PROMPT/buildUserMessage; add extractor + prompt tests. * freshness: tighten system prompt for author noise + calibration - PRECISION: prefer no finding over a speculative one; report each issue once. - OUTPUT vs CODE: never flag staleness/secrets inside illustrative output blocks. - SEVERITY defined by reader impact (fails today / deprecated path / cosmetic). - SCOPE: skip prose, screenshots, product-name currency, deliberate simplifications. - GROUNDING: quote the offending token; flag training-data inferences as Low. Reframes the reviewer as helping the tutorial AUTHOR. Adds prompt-guard tests. * perf(rebuild): cache node_modules to skip ~48s npm ci on unchanged lockfiles setup-node's 'cache: npm' already warms ~/.npm, but 'npm ci' still spends ~48s extracting/linking 1680 packages + native builds into node_modules on every rebuild run (verified in run 32783495862: cache restored, yet 'added 1680 packages in 48s'). Cache the materialized node_modules (root + hugo-apps) on an exact lockfile key and skip the install on hit. Exact-key only (no restore-keys): skipping 'npm ci' means a mismatched tree would go unreconciled, so any lockfile change must miss and reinstall clean. Safe because neither package.json has install/prepare/postinstall lifecycle scripts -- nothing outside node_modules is produced at install time. * docs(openspec): propose slug-targeted delta rebuild (O(changed) end-to-end) Design + specs + tasks for making a single-tutorial rebuild scale with changed slugs instead of the full corpus. Four independently-shippable workstreams, grounded in code research (file:line): - content-delta-publish: mutable ContentCurrent + append-only ContentHistory replaces full-snapshot-per-version + carryForwardUnchanged (~95s server cost) - generated-content-cache: cache hugo/content/tutorials (~25MB) with a correctness-first key (hashes /build feeds + parser source + per-slug source) - single-slug-render: scoped Hugo render (R2 verified coherent) - tutorial-discovery: unmask GraphQL errors + fix App-token org-node auth + loud REST fallback Companion CI win (node_modules cache) shipped separately in #2016. * fix(fetch): unmask GraphQL discovery errors + loud REST fallback graphqlRequest warn-logged a GraphQL errors/null-data response and returned the null data, so callers dereferenced data.organization/data.repository and threw an opaque TypeError — which the outer catch mistook for an outage and SILENTLY degraded discovery to the slow per-slug REST path (~1400 extra calls, secondary-rate-limit risk) every rebuild. - graphqlRequest now throws a typed GraphqlError carrying the GraphQL error type+message; throws on errors[] or null data. - GraphqlError.isAuthError classifies FORBIDDEN/INSUFFICIENT_SCOPES/permission failures (the App-installation-token org-node gap). - discovery + metadata-batch fallbacks log at ERROR level (once) when the cause is an auth/permission error, so a token-scope regression is visible instead of hidden as latency. Workstream A of the slug-targeted-delta-rebuild design (#2017). The auth fix itself (repo-oriented discovery vs PAT vs App Org:Read) is Workstream B and gated on the real error this now surfaces on DEV. Test: test/unit/github-graphql-error-unmask.test.ts (6 cases). * feat(rebuild): generated-content cache helpers (Workstream C foundation) Pure, tested helpers for the slug-targeted fast path: feed fingerprint (catalog/co-completions/tag-labels), sidecar read/write, fast-path eligibility decision, and navEntries-by-slug reconstruction. Fail-open throughout. Nothing calls these yet — the fetch-tutorials.ts reuse wiring (flag-gated, requires a byte-identical DEV diff-verify) + the actions/cache workflow step land next. Test: test/unit/content-cache.test.ts (15 cases). * feat(rebuild): wire generated-content fast path (Workstream C, flag-gated off) On a slug-targeted run with CONTENT_CACHE_FAST_PATH=true, fetch-tutorials reuses the previously-generated .md + sidecar nav/author rows for non-target slugs, skipping composeTutorial/fetchRulesVr/AI-quiz/writeHugoPage — the bulk of Phase 3's ~56s. Two gates, both required, else full regen: - actions/cache KEY = parser-source hash (a parser change → cache miss → the per-slug existsSync guard falls through to recompose) - runtime feed fingerprint over CAP catalog + tag-labels (nav/mission/tags); co-completions excluded (empty on warm-cache runs, recommendations are client-hydrated) Sidecar (navEntries + authorRows + fingerprint) written to .content-cache/, cached by the same parser-hashed key as hugo/content/tutorials + image_dimensions.json. Fail-open throughout; flag defaults OFF so default behavior is byte-identical to today. Enabling on DEV (input content-cache=true) + a byte-identical diff-verify (task 3.6) is the follow-up before flipping the default. Helper unchanged behavior; content-cache tests green (15). * feat(db): add ContentCurrent + ContentHistory aspects/entities (Option B schema, Workstream D) Mutable current-content table (one row per slug, no version column) + append-only per-(version,slug) history carrying the BLOB for self-contained rollback replay (design.md D1/D2). Mirrored into the QA namespace. Verified: full model compiles + deploys to sqlite::memory:. NEXT (gated, not in this commit): .hdbmigrationtable staging for the two new HANA tables (db/src/ + db/last-dev/ regen via the project's cds-build-staging procedure) + hybrid deploy verify — the version-counter-hazard step. Then write path (dual-write, flag), readers, rollback. * feat(publish): Option B dual-write to ContentCurrent + ContentHistory (Workstream D, flag-gated) commitSession now mirrors freshly-published slugs into the mutable ContentCurrent (UPSERT, one row per slug) + append-only ContentHistory (WRITTEN rows) when CONTENT_DELTA_WRITE_ENABLED=true, alongside the legacy ContentFiles write. Chunked BLOB read mirrors carryForwardUnchanged (raw db.run on HANA for the LOB-locator path, CQL on SQLite). Fail-SAFE: never throws into the commit tx — legacy ContentFiles stays the source of truth until the reader cutover. Tests (SQLite): test/unit/content-delta-dualwrite.test.js (4) — one-row-per-slug, UPSERT on republish, history append per version, flag-off writes neither. Existing commit-path tests still green (carryforward-memory + guard, 12). HANA LOB path is covered by the hybrid publish→rollback test (task 7.4). * fix(#2023): stop Hugo YAML 1.1 coercing yes/no quiz options to booleans rules.vr answer options like [ ] no / [x] yes rendered as false/true (and a yes/no correctAnswer flipped to a boolean) because the frontmatter serializer emits bare yes/no/on/off tokens under YAML 1.2, which Hugo's YAML 1.1 parser then reads as booleans. jsonify ships those booleans into