feat(dashboard): add the feature-videos catalog and display-state API - #9168
Conversation
Design Review (Fable 5) — ✅ PASSDesign-level review of Design-Verdict: PASS Deterministic catalog + permanent local state is the right shape for shipped-artifact intros, correctly not the tips engine; boundaries, failure directions, and the split-PR contract are all reasoned and tested. [DESIGN-REVIEWED] 69c7b9d |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All evidence is in: the contract, the intent file, the full patch, and repo greps to verify consumer counts ( First-Principles-Verdict: CONCERNS
What this change shipsIntent: let a fresh install be shown a short intro clip for a feature it hasn't used, at most once, ever — an ADDITION (backend half; frontend rides in a parallel PR).
Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 69c7b9d |
Opus 4.8 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
9f4534f to
910d98a
Compare
Not overridden, even though the machine-drafted override rationale is factually right about reachability. It named the reason to fix rather than the reason to waive: the module's own contract says this loader degrades.
Three regression tests, one per reader, each writing a document nested |
Taken as written. The line now reads Regression test asserts the string Scope note: |
910d98a to
8c4d7d9
Compare
|
First Principles Review — 🟡 CONCERNS — one subtraction taken, two rebutted, both Watch items answered. Head The premise is accepted as stated: merged alone this ships an API with no in-tree caller. That is the declared shape of the work item — the frontend Subtraction 3 — drop the
Correct, and it turned my own argument against me properly. Catalog membership is strictly tighter than a character count, so the length branch could never be the reason any id that mattered was refused, while shipping a second permanent Subtraction 1 — drop
The count is right and the general instinct is right. It does not apply because this field is not authored generality — it is part of the API contract this work item was given, and the payload key is consumed by the parallel frontend that is being built against it right now. Removing and re-adding a payload key is exactly the narrow-later problem the review correctly cites for a Subtraction 2 — drop
Also accurate. Both probes were named in the work item as the registry's initial set, so they are the specified surface rather than speculative extension, and each has tests that pin its real behaviour — Watch — Watch — merge order decides whether |
Adds the backend half of startup feature-intro clips: a static catalog, a
deterministic eligibility rule set, and three routes registered beside the
tips routes.
Tips are generated, so their engine is a cadence gate over a pool that
changes every six hours. A video is a recorded artifact, so nothing about it
can be generated at request time and there is one right answer per install
state. Selection therefore walks a static tuple in catalog order and returns
the first eligible entry, and "has the user already found this feature?" is
answered by named probes over local state rather than by a model.
- GET /api/feature-videos/next -> {video, enabled}; the first entry that is
enabled, unrecorded, version-satisfied, and not withdrawn by a used_when
probe. Temporary and incognito sessions get null, because the state a
video records is permanent and instance-wide.
- POST /api/feature-videos/feedback {id, status} -> {ok: true}. seen and
dismissed are both permanent; there is no snooze, because a feature intro
that comes back is noise. An id outside the catalog is a coded 400, so the
state file cannot accumulate client-supplied keys.
- GET /api/feature-videos/status -> {enabled, state} for the settings panel.
src and poster are same-origin paths under /app-assets/feature-videos/,
validated by one function that refuses any scheme, //, .., %, a backslash,
whitespace, and anything outside the prefix: a clip src is fetched by the
browser with the dashboard's own credentials, so an off-origin value there
is an outbound request the user authorized without knowing it. Remote-hosted
clips are a separate future change and the relaxation belongs in that one
function.
Probes are cheap, run at most once per /next request, and only for entries
no earlier check already ruled out. A probe that raises and a signal nobody
registered both count as "not used" and are logged: the failure mode is one
clip a user may not need, where the opposite default would silently withhold
every intro on a host whose audit log is unreadable.
dashboard.feature_videos_enabled is the instance kill switch, wired where
tips_enabled is defined and parsed. State lives in
feature_videos_state.json beside tips_state.json, written owner-only.
No CHANGELOG entry: a feature PR does not touch that file (docs/build/
changelog.md), and check_changelog_history.py enforces it.
8c4d7d9 to
69c7b9d
Compare
The defect holds. The suggested predicate is the wrong half of the product's split, so I used the other one.
Two tests: a read-blocking session gets |
|
First Principles Review — 🟡 CONCERNS (round 3 on this span) — one argument conceded on mechanism, four subtractions held, and one question put to the maintainer. No code change this round, deliberately.
This is a better argument than the count, and it defeats the defence I gave last round. I said a clip is a shipped binary that can be recorded ahead of its code; that is true of the ASSET but not of the ENTRY, and the entry is what carries the floor. Compiled into the same wheel, an old build cannot contain a new entry, so the guard is unreachable today. I am still not removing it in this PR, and the reason is not the finding — it is who owns the call. Maintainer, this is the one decision I am asking for: trim the contract to only what has a consumer today (drop
Shrink On the round count. This is the third round in which this lane has proposed the same subtractions, and each one now trades against a contract another in-flight change depends on rather than against code I can freely edit. Per the loop's same-span rule I am not patching further here; the invariant that answers all of them at once is the maintainer decision above. |
Review-ready — final summaryHead What this is. The backend half of startup feature-intro videos: a static catalog, a deterministic eligibility rule set, and three routes registered beside the tips routes. The frontend Reviewer rounds, and what each changed.
Every finding has its own disposition comment. Fixed, in order: One decision is open for a maintainer, in the round-3 First Principles disposition: keep the frozen cross-session API contract, or trim Two reds on this PR were never this PR's. 106 tests in |
bolichen97
left a comment
There was a problem hiding this comment.
Tech Lead review — approve.
Per-user scoping of display state: correct. State is config_dir()/feature_videos_state.json, written through atomic_write(restrict_to_owner=True) (0600 on POSIX, owner-only DACL on Windows), sitting beside tips_state.json and reached through the same config_dir() helper — so it inherits KIROCREW_HOME expansion and unsafe-system-directory rejection rather than a raw environ read. That is per-install owner state, which is the only user boundary KiroCrew's owner-gated dashboard has; there is no global or shared 'has seen' flag and no cross-account surface to leak into. The restricted-session split is the right half on each side: /next and feedback gate on _is_restricted_session (temporary and incognito neither see a clip nor leave a row), while /status gates on the narrower _blocks_reads_session so an incognito session still renders its own settings panel. Gating the write side matters more than the read side here, since the write is what creates the permanent row.
Scope: proportionate. 11 files, +1639/-0, no deletions, one commit. The 659-line module is one new concern; 866 of the added lines are tests. Nothing existing is refactored — three routes registered beside the tips routes, one config key added where tips_enabled is defined and parsed, and a regenerated config-baseline.json row.
Blocking findings: none unresolved. GPT 5.6 and Opus 4.8 both report no blocking findings on 69c7b9d69; Design is PASS; First Principles is advisory CONCERNS with every subtraction dispositioned in a per-finding comment. Zero human reviews requesting changes, zero unresolved threads. The two GPT findings that were real got fixed rather than waived — RecursionError escaping load_state's documented degrade-to-empty contract (fixed in all three readers of an operator-writable file, not just the flagged line), and bool("false") is True leaving a kill switch on (now through _safe_bool). The /status engagement-history leak to restricted sessions was also a genuine find and is fixed. I accept the min_version needs-a-decision item as a maintainer call: keep it. The counter-argument that catalog entry and running version travel together is correct on mechanism, but this is a frozen contract the parallel frontend is being built against, and re-adding a payload key later is the same narrow-later cost that review rightly flags about error codes.
i18n: nothing owed. The diff touches zero website/ files, so no locale catalog obligation and the ux-review-required ruleset does not apply. The catalog's English title/description are backend-supplied display copy, which is exactly what tips.py already serves through its title/body fields — a pre-existing repo-wide pattern, not a regression this PR introduces.
Sequencing vs #9169: no base dependency, but an order. #9169's base is main, not this branch, and the two diffs share zero files — so nothing is stacked and neither blocks the other mechanically. The logical order is still backend-first: #9169 is the half that calls these endpoints and ships the clip files. Merged alone, this PR's /next would return an entry whose src 404s, but no in-tree caller exists yet, so no user reaches it. The reverse order would ship a modal calling routes that do not exist. Merging this first is the safe direction.
CI. 56 success / 9 skipped on the head. The six cancelled check-runs (Automated Rule Check, GPT 5.6 Review, Inclusive Language, PR Hygiene, SAST, Screenshot Evidence) each have a later success run on the same SHA — superseded, not an unresolved gap, so the readiness signal is honest.
The backend landed in #9168 with `dashboard.feature_videos_enabled` defaulting to `true`. Nothing shows yet only because no frontend mounts the dialog, so the moment #9169 merges every install starts playing a clip at startup -- a feature nobody has used end to end, with placeholder media rather than real recordings. A startup dialog is the most intrusive surface here, and its verdict is permanent: watch or close a clip and it never comes back. Turning it on should be a deliberate decision, not a side effect of a frontend PR merging. The switch already works; only its direction changes. The default flips in the two places that decide it -- the dataclass field and the loader's fallback for a config that does not mention the key -- and `config-baseline.json` is regenerated from the dataclass registry, which records it in two spots. Both docs pages now say `false`, and the feature-videos controls table names the ON switch rather than only the OFF one. The three tests in `TestConfigFlag` that pinned the old default now pin the new one; the non-bool case is more load-bearing than before, since `bool("false")` is `True`. A pause, not a retreat: turn it on locally, record real clips, then flip the default back in its own change.
…t on disk Two changes to the same gate, both about not showing a clip nobody should see yet. Neither touches selection order, the probes, or verdict permanence. 1. `dashboard.feature_videos_enabled` defaults to `false`. The backend landed in #9168 defaulting to `true`; nothing shows only because no frontend mounts the dialog yet, so the moment #9169 merges every install would start playing a clip at startup with placeholder media. A startup dialog is the most intrusive surface here and its verdict is permanent, so turning it on should be a deliberate decision. Flipped in the dataclass field and the loader fallback; `config-baseline.json` regenerated. 2. "Asset shipped" is now a precondition of "on offer". `_entry_is_valid` checked the SHAPE of `src`/`poster` but never whether the file existed, so the catalog offered entries whose media is not shipped. The frontend cannot catch that: its `<video>` is `preload="none"`, so nothing is fetched -- and no media error can fire -- until the user presses play. The dialog opens on the JSON alone, around a blank player, and "Got it" writes a permanent `seen` that retires the real intro before anyone saw it. New `offerable()` = `catalog()` filtered to entries whose clip AND poster are on disk under `static/dist/app-assets`; `select_next` walks that. `catalog()` keeps structural-only semantics on purpose, because the feedback route checks membership against it and a user already shown a clip must still be able to record a verdict if its asset later vanishes. Tests: the three `TestConfigFlag` cases pin the new default (the non-bool case is MORE load-bearing now, since `bool("false")` is `True`); an autouse fixture treats media as shipped so the 100+ selection/route tests keep testing what they are about; `TestAssetExistenceGate` (7 cases) replaces that default with a real temp directory and covers the URL->disk mapping, withholding on a missing clip or poster, skipping past an unshipped entry, recovery once the clip lands, and that `catalog()` and `offerable()` genuinely differ. Mutation-verified: routing `select_next` back through `catalog()` fails 3 of the 7. A pause, not a retreat: turn it on locally, record real clips, then flip the default back in its own change. The existence gate stays.
…t on disk Two changes to the same gate, both about not showing a clip nobody should see yet. Neither touches selection order, the probes, or verdict permanence. 1. `dashboard.feature_videos_enabled` defaults to `false`. The backend landed in #9168 defaulting to `true`; nothing shows only because no frontend mounts the dialog yet, so the moment #9169 merges every install would start playing a clip at startup with placeholder media. A startup dialog is the most intrusive surface here and its verdict is permanent, so turning it on should be a deliberate decision. Flipped in the dataclass field and the loader fallback; `config-baseline.json` regenerated. 2. "Asset shipped" is now a precondition of "on offer". `_entry_is_valid` checked the SHAPE of `src`/`poster` but never whether the file existed, so the catalog offered entries whose media is not shipped. The frontend cannot catch that: its `<video>` is `preload="none"`, so nothing is fetched -- and no media error can fire -- until the user presses play. The dialog opens on the JSON alone, around a blank player, and "Got it" writes a permanent `seen` that retires the real intro before anyone saw it. New `offerable()` = `catalog()` filtered to entries whose clip AND poster are on disk under `static/dist/app-assets`; `select_next` walks that. `catalog()` keeps structural-only semantics on purpose, because the feedback route checks membership against it and a user already shown a clip must still be able to record a verdict if its asset later vanishes. Tests: the three `TestConfigFlag` cases pin the new default (the non-bool case is MORE load-bearing now, since `bool("false")` is `True`); an autouse fixture treats media as shipped so the 100+ selection/route tests keep testing what they are about; `TestAssetExistenceGate` (7 cases) replaces that default with a real temp directory and covers the URL->disk mapping, withholding on a missing clip or poster, skipping past an unshipped entry, recovery once the clip lands, and that `catalog()` and `offerable()` genuinely differ. Mutation-verified: routing `select_next` back through `catalog()` fails 3 of the 7. A pause, not a retreat: turn it on locally, record real clips, then flip the default back in its own change. The existence gate stays.
…t on disk (#9315) Two changes to the same gate, both about not showing a clip nobody should see yet. Neither touches selection order, the probes, or verdict permanence. 1. `dashboard.feature_videos_enabled` defaults to `false`. The backend landed in #9168 defaulting to `true`; nothing shows only because no frontend mounts the dialog yet, so the moment #9169 merges every install would start playing a clip at startup with placeholder media. A startup dialog is the most intrusive surface here and its verdict is permanent, so turning it on should be a deliberate decision. Flipped in the dataclass field and the loader fallback; `config-baseline.json` regenerated. 2. "Asset shipped" is now a precondition of "on offer". `_entry_is_valid` checked the SHAPE of `src`/`poster` but never whether the file existed, so the catalog offered entries whose media is not shipped. The frontend cannot catch that: its `<video>` is `preload="none"`, so nothing is fetched -- and no media error can fire -- until the user presses play. The dialog opens on the JSON alone, around a blank player, and "Got it" writes a permanent `seen` that retires the real intro before anyone saw it. New `offerable()` = `catalog()` filtered to entries whose clip AND poster are on disk under `static/dist/app-assets`; `select_next` walks that. `catalog()` keeps structural-only semantics on purpose, because the feedback route checks membership against it and a user already shown a clip must still be able to record a verdict if its asset later vanishes. Tests: the three `TestConfigFlag` cases pin the new default (the non-bool case is MORE load-bearing now, since `bool("false")` is `True`); an autouse fixture treats media as shipped so the 100+ selection/route tests keep testing what they are about; `TestAssetExistenceGate` (7 cases) replaces that default with a real temp directory and covers the URL->disk mapping, withholding on a missing clip or poster, skipping past an unshipped entry, recovery once the clip lands, and that `catalog()` and `offerable()` genuinely differ. Mutation-verified: routing `select_next` back through `catalog()` fails 3 of the 7. A pause, not a retreat: turn it on locally, record real clips, then flip the default back in its own change. The existence gate stays. Co-authored-by: Zejiang Guo <zejiangg@amazon.com>
Problem / Motivation
A new install has no way to be shown a feature. Feature Tips describe one in a line of text above the composer, which works for a config toggle or a keyboard shortcut but not for anything you have to watch to understand — a monitor loop following a pull request, a tip card arriving mid-turn. There is no catalog of recorded intros, no rule for picking one, and no record of which ones a user has already seen.
This PR is the backend half: the catalog, the eligibility rule set, and the API. A parallel change builds the
StartupVideoModalthat plays them, and ships the clip and poster files underwebsite/public/app-assets/feature-videos/.Why it matters
Features nobody discovers are features nobody has. Tips already carry that job for text-shaped features and are measurably the right shape for them; the ones a still line of prose cannot convey are exactly the ones a fresh install is least likely to find on its own.
Getting the selection rule right is the part that decides whether this is welcome or annoying. An intro for something you already use every day is worse than no intro, so "have you found this yet?" has to be answered from local state rather than guessed — and it has to be answered the same way twice, or a modal flickers between clips on two polls a second apart.
What changed (motivation → approach → change)
Goal: show a fresh install one short clip for a feature it has not used, at most once per feature, ever.
Approach, and why it is not the tips engine. Tips are generated: a model picks a feature and writes prose, so their engine is a cadence gate plus a weighted-random selector over a pool that regenerates every six hours. A video is a recorded artifact — the clip either exists or it does not — so nothing about it can be produced at request time, and for a given install state there is exactly one right answer. Modelling it on tips would have bought randomness nobody wants and a six-hourly refresh with nothing to refresh.
So the rule set is deterministic:
feature_videos.py— no doc scan, no LLM;What was built. New module
src/kiro_crew/feature_videos.py, three routes registered beside the tips routes indashboard/routes/realtime.py, and one config flag wired wheretips_enabledis defined and parsed.An entry is eligible when the kill switch is on, no status is recorded for it,
min_versionis satisfied, and noused_whenprobe fires. Decisions worth naming:seenanddismissedbehave identically and there is no snooze: a feature intro that comes back is noise, not a reminder.srcis fetched by the browser with the dashboard's own credentials, so an off-origin value there is an outbound request the user authorized without knowing it.validate_asset_pathrefuses any:(every scheme, plus a Windows drive letter),//,..,%(so a percent-encoded traversal cannot reconstitute one after the browser decodes it), a backslash, whitespace, and anything outside/app-assets/feature-videos/. Remote-hosted clips are a separate future change and the allowlist relaxation belongs in that function alone — the comment says so at the line it would go.docoutside the tips doc allowlist, logs a warning and withdraws that one entry rather than 500ing all three endpoints./nextrequest and only for entries no earlier check already ruled out.artifacts_nonemptystops at the first artifact directory rather than going throughArtifactStore.list(), which reads everymeta.json.sel_event_seenuses the bounded tail-firstsel().recent(limit=…).config_key_setreads the config FILES, not the effective config. Every effective key has a value, so an effective read would fire on the shipped default and withdraw the clip from someone who never touched the setting.nullfrom/next, andfeedbackrecords nothing and still answers{"ok": true}— the write side is where the permanent row actually lands, so gating only the read would leave the trace one POST away.enabled: falseis a body, not a 204. The settings panel and the modal both have to tell "the operator turned this off" apart from "nothing left to show", and a bodiless response cannot.State lives in
feature_videos_state.jsonbesidetips_state.json, written throughatomic_write(restrict_to_owner=True, restrict_on_error="warn")— the file records which features this user engaged with, which is a behavioural profile.record_statusholds a lock across load-mutate-save so two tabs recording different videos cannot drop each other's row.Catalog seeded with two entries (
feature-tips,monitor-loops) pointing at<id>.mp4/<id>.jpg.Deliberately untouched:
/api/dashboard/configand everything undercapabilities.social_share— the frontend reuses the existingsocial_share_enabledfor its share button.Signal from
diff_signals.py:config/infra file changed— that isconfig-baseline.json, regenerated byscripts/generate_config_baseline.pyfor the one added key, plus thedashboard.feature_videos_enabledrow insections.py/loader.py.No CHANGELOG entry. A feature PR does not touch that file (
docs/build/changelog.md), andcheck_changelog_history.pyenforces it; the release PR writes the section.Tests
test/test_feature_videos.py, 106 tests. What each group locks in://, embedded//,..,..%2f,%2e%2e, backslash, whitespace, newline, wrong prefix, bare prefix, non-string) and 3 acceptances./nextskips — aseenentry, adismissedentry, an entry whose probe fires, an entry withdrawn by any one of several signals, and a version-gated entry; plus that probes are not run for an entry state already ruled out, and that five consecutive calls return the same id.0600, and 8 parametrized bad bodies each answer 400 with the rightcode; an oversized id is refused asunknown_videoby catalog membership rather than by a length branch, and a rejected body writes no state file at all./nextand/statusboth reportenabled: falsewith no video and no state./nextreturns null while still reportingenabled: true;feedbackwrites no file;/statusserves an empty state map to a read-blocking session but still serves its own map to an incognito one, so the product's read/write split cannot collapse.tsis zeroed rather than dropping the row, a 400-digit integerts(which raisesOverflowError, notValueError) does not 500 the loader, and neither does a document nested past the recursion limit (RecursionError) in any of the three files this module reads.config_key_setdoes not fire on a shipped default, thattips_feedback_existsfires on an opt-out whose collections are all empty, that a corrupt tips state file is tolerated, and that the SEL read is bounded to the declared limit.<id>.mp4/<id>.jpg, an invalid entry is filtered rather than raised, andused_whennever reaches the client payload."false") keeps the default rather than reading as on.Manual verification
N/A — unit coverage sufficient. Every route is exercised end-to-end against the real state file through the same helpers the gateway calls, and the one thing tests cannot cover is playback of clip files this PR deliberately does not ship (the parallel frontend change ships them, and the frontend session drives that verification).
Related Issues
no linked issue: one work item of a larger "startup feature-intro videos" change, tracked outside the issue tracker.
Checklist
src/kiro_crew/docs/feature-videos.md(new, indexed in both docs indexes), thedashboard.feature_videos_enabledrow inconfiguration.md, and the owning specdocs/system-specs/modules/learn-cron-dashboard.mdRound 2 (head
910d98a7a)The GPT lane returned one BLOCKING and one advisory finding on
9f4534f13. Both were legitimate one-line fixes and both are fixed; each has its own disposition comment on this PR.json.loadsraisesRecursionError, which is neitherOSErrornorValueError, so a state file nested past the recursion limit escaped the loader'sexceptand 500'd every endpoint — againstload_state's own documented promise to degrade. The fix catches it in all three readers of an operator-writable file, not only the line the finding named, because fixing one would have left the same 500 one probe away on the same request path. The advisory finding wasbool("false") is True: a kill switch an operator wrote as a string stayed on. That line now parses through_safe_bool.One further defect was mine, found by the full backend suite rather than by a reviewer:
test_opt_out_withdraws_the_tips_videoran against the SHIPPED catalog, so its second entry'ssel_event_seenprobe read the host's real audit log and any box that had ever calledmonitor_startfailed the assertion. The test now pins the catalog to the tips entry plus one signal-free control, so it cannot reach the audit log at all.Round 3 (head
8c4d7d900)Readiness passed on
910d98a7awith every lane green. The First Principles lane returned advisory CONCERNS naming three subtractions, and one of them was right in a way that only stays cheap before a client exists: thevideo_id_too_longbranch shipped a second permanent errorcodefor a case theunknown_videocatalog-membership check already covers, and membership is the strictly tighter bound. That branch is gone; a 101-character id now answersunknown_video, and a new test sends 5000 characters to show one code covers every non-slug id._VIDEO_ID_MAX_CHARSremains only as the catalog validator's own bound.The other two subtractions — drop
min_version, drop the two probes no catalog entry names — were accurate counts but are rebutted: both are the API surface this work item specified, the parallel frontend is being built against the payload as frozen, and re-adding a payload key later is the narrow-later problem the same review correctly raises about error codes. Each subtraction and both Watch items have their own reasoning in a disposition comment on this PR.Round 4 (head
69c7b9d69)Two things, one of them not this PR's.
The CI red on
8c4d7d900was main's, not this branch's.test/test_security.py::TestIsSensitiveBashCommand::test_chained_cd_expansions_do_not_blow_up_the_gatepatchedkiro_crew.security._dir_holds_sensitive_leaf, a helper #9089 had removed, so it failed on Backend Tests shard 3 for Linux and Windows alike and took the Coverage Gate down with it (coverage-combine skips when the backend lane fails, and the gate fails closed). It reproduced on a pristineorigin/mainworktree with this diff nowhere in it, and it is filed as #9184. Main's own repair landed ascbdd4a569; rebasing onto it clears the red with no change to this diff, and the previously-red test now passes locally on the new base.The GPT lane's one advisory finding was legitimate and is fixed:
/statusreturned the full engagement-history map to any session, so a restricted session could read which features this owner had watched. It now gates on_blocks_reads_sessionrather than the suggested_is_restricted_session, because that is the product's own split — incognito withholds writes, a temporary session withholds reads too — and the broader predicate would also have blanked an incognito session's own settings panel.enabledstays truthful to every session, since the kill switch is configuration rather than history.Local verification
All 47 resolved profile gates green on this head, including
check_black_formatting,check_sync_io_in_async,check_loop_bound_locks,check_brand_name,check_harness_parity,check_changelog_history,docs-lint,scrub-lint --no-history,verify_vendor_manifest,isort,flake8, andmypy(1304 files clean).Full backend suite: 90127 passed, 96 failed. All 96 are pre-existing host-environment failures on this box, unchanged in count and class from the same suite run against this branch before the review round —
/local/homeowned by uid 65534, xdist host-budget assertions reading the live core count, Electron symbols-manifest paths, and aghbinary probe. None are intest/test_feature_videos.pyor any file this diff touches.Both local review lanes (GPT contract, Opus contract) returned PASS with no blocking findings. Five non-blocking findings were legitimate and are fixed in this head: the tips opt-out signal, the missing write-side restricted-session gate, the
OverflowErroron an oversized persisted timestamp, the unsynchronized read-modify-write, and three in-function imports now hoisted. One finding was rebutted — the absent asset files are the parallel frontend change's to ship, by design. One half of another was rebutted: addingconfig_key_set:dashboard.tips_enabledto the tips entry would fire on presence, so a user who explicitly set that key totruewould lose the clip.