Native picker data injection: global boards as native GitHub UI (spec 008, v0.7.0) - #15
Merged
Conversation
Investigation + PoC (2026-08-19): inject global boards into GitHub's own picker data feeds instead of rendering custom UI. Issue pages validated end to end (native render, cross-org native add, native sidebar display); PR legacy pages render natively but need extension-performed mutations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… v0.16.5 template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…uickstart Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…points Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ode) New document_start content script + main-world injector that augments GitHub's picker feeds with configured global boards: item-pickers feed and IssueViewerViewQuery on issues (plus Relay store membership commit and IndexedDB persister seeding), projects_suggestions and sidebar form POST delegation on legacy PR pages. Native mutations on injected rows are observed to keep membership state coherent. All paths fail open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tics; docs Live validation (quickstart V1-V8) on canonical URLs via isolated dev Chrome: native render, cross-org native add AND delete on issues, Relay membership commit after reload (with hydration retry), PR picker render plus delegated add/remove. Fixes from validation: Relay environment discovery via react-app reactRoot container key with iterative walk; legacy PR form serializes every listed project with the value carrying state (on/empty). Custom picker UI (global-boards-picker.ts, CSS block, issue-sidebar wiring) removed; docs updated (page layout data-layer section, picker status, AGENT.md). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rg; drop FilOzone/* from proactive defaults Same-org invariant now enforced in the injector's config handler (single choke point) in addition to the content-script filter. FilOzone/* removed from DEFAULT_TARGET_REPOS: the FOC board lives in that org, so native GitHub UI already covers membership there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The committed Relay edge is now enriched with the board's Status field definition and the item's Status value, fetched via GitHub's own ProjectItemSectionFieldListQuery (node-by-id, served cross-org over session cookies). Result: the injected project card renders identically to same-org boards — collapsed Status row, expandable field list that GitHub lazily fetches itself, and native field editing (updateProjectItemFieldValueMutation, verified accepted cross-org with change+revert on solstice#9). Cleanups per user direction: FOC field card no longer renders on issue pages (legacy PR pages keep it, where GitHub cannot show cross-org boards); IssueViewerViewQuery response augmentation removed in favor of the single Relay-commit mechanism; canonical terminology section added to docs/github-page-layout.md (Projects section / project card / Projects picker / FOC field card). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n issue/PR pages Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… document fragments-vs-queries rationale The injector now harvests the current ProjectItemSectionFieldListQuery hash from GitHub's own requests (fired on any project card expansion, observed even while dormant) into localStorage, and Status enrichment tries the cached hash before the hardcoded seed. A rotation therefore self-heals after one organic card expansion; until then only the collapsed Status row is omitted, with a console warning. Docs: research.md gains 'Why the extension must source the collapsed Status itself', explaining Relay fragment-backed (read-only) vs query-backed (self-fetching) components and why the spec 007 invalidate-and-refetch trick cannot work here (IssueViewerViewQuery responses are server-filtered on every request, so a refetch can never deliver the cross-org edge). Layout doc and status doc updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… rename column to 'On FOC board'; compact tables go-fil-commp-hashhash is in filecoin-project and therefore proactive, so it cannot serve as the scenario 4 fixture, and frisbii is read-only for the team, so it moves to a dedicated read-only-viewer fixture note. Scenarios 4 and 6 now use BigLep/.github items (4/5 verified on the FOC board, 6/7 verified off it). Tables normalized to compact pipes without column padding; fixes two formatter regressions (corrupted ipld org name, inverted markdown link). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…otocol); document query limitations
GitHub's REST board-items search (?q=) answers from an eventually
consistent index that lags mutations by minutes in both directions,
and both GraphQL alternatives are unavailable: ProjectV2.items has no
server-side content filter, and the content-side projectItems
connection filters cross-org memberships out (presence proves
membership, absence proves nothing). A full items scan was rejected on
cost (thousands of items, worst case paid on every not-member check).
The delegated picker toggle therefore forwards its mutation result as
an authoritative hint via filoz:boards-changed detail; issue-sidebar
persists it per tab (sessionStorage, 5 min TTL) and passes it to
GET_PANEL_STATE, where the worker skips the REST search and resolves
field values live by item node id. Removal also clears the FOC field
card DOM immediately. Same-org boards ignore the hint: content-side
GraphQL is live and unfiltered there, hence authoritative on its own.
Verified live on filecoin-pin PR#1: add renders the card in ~5s, remove
clears it instantly, and a reload inside the index-lag window no longer
resurrects stale state. Full write-up in research.md ('Membership
resolution: the queries we wish we could run...') and the status doc.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…measured index lag A global board in the same org as the viewed repo is GitHub's business: it renders and manages membership natively, so the extension now skips same-org everywhere instead of special-casing it. Deletes the same-org GraphQL membership path (QUERY_NODE_PROJECT_ITEMS, matchProjectItem, NodeWithItems), adds early skips in the card layer and both worker resolvers, and makes the membership hint unconditional in the remaining cross-org path. This also makes re-adding FilOzone/* to the proactive defaults harmless if ever desired. Hint TTL raised 5 -> 30 minutes: search index convergence was measured taking up to ~20 minutes, so a couple-of-minutes TTL let stale search results win again after expiry. Docs updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mbership lookups Opening many tabs at once (the canonical test URL set) can trip GitHub's secondary rate limit; both the arming path (GET_NATIVE_PICKER_BOARDS) and membership resolution (GET_GLOBAL_BOARDS_STATE) were one-shot on failure, leaving a tab permanently dormant (observed: solstice#9 missing its native FOC card, BigLep/.github#4 dormant with an unchecked stale picker row). Both now retry with backoff (15s/30s/45s, budget reset per page), and the worker dedupes concurrent identical membership lookups so a proactive page load costs one REST scan instead of two (card layer + picker layer). Verified live: burst-reloading the open test tabs yields correct state everywhere; the scenario 4 lazy flow works as designed (picker open resolves membership, FOC shows checked, native card renders). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR implements spec 008’s shift from an extension-rendered “global boards” picker UI to data-layer interception so GitHub renders global boards as native rows/cards, and it refreshes Spec Kit workflow assets used to generate and execute specs/plans/tasks. It also bumps the extension/package version to 0.7.0 and updates docs/manual validation guidance accordingly.
Changes:
- Adds the native-picker injection pipeline (document_start content script + web-accessible main-world injector) and supporting types/caching hooks so GitHub’s own Projects picker/sidebar can display and mutate cross-org boards natively.
- Retires the previous custom global-boards picker UI and associated CSS; updates sidebar logic to avoid duplicate UI on issue pages.
- Updates specs/docs and Spec Kit workflow/templates/scripts to match the new “dash-syntax” commands and newer Spec Kit behaviors.
Reviewed changes
Copilot reviewed 73 out of 73 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| specs/008-native-picker-data-injection/tasks.md | Task breakdown for spec 008 implementation and validation checkpoints |
| specs/008-native-picker-data-injection/spec.md | Feature requirements, scenarios, and acceptance criteria for native injection |
| specs/008-native-picker-data-injection/quickstart.md | Manual validation steps and recorded results for spec 008 |
| specs/008-native-picker-data-injection/plan.md | Technical plan for intercepting feeds/Relay/IDB and retiring custom UI |
| specs/008-native-picker-data-injection/data-model.md | Data entities and cache/edge shapes used by native-picker injection |
| specs/008-native-picker-data-injection/contracts/messages.md | Event/message contracts across isolated world ↔ main world ↔ service worker |
| specs/008-native-picker-data-injection/contracts/github-feeds.md | Documented GitHub endpoints/payloads targeted by the injector |
| specs/008-native-picker-data-injection/checklists/requirements.md | Spec quality checklist for the feature spec |
| scripts/build.mjs | Builds new native-picker bundles into extension/dist/ |
| package.json | Version bump to 0.7.0 |
| extension/src/styles/sidebar.css | Removes CSS for the retired custom picker UI |
| extension/src/lib/queries.ts | Extends project query fields; removes unused project-items query |
| extension/src/lib/project-config.ts | Removes FilOzone/* from proactive defaults; keeps URL parsing helpers |
| extension/src/lib/messages.ts | Adds types/messages used by native-picker configuration/membership hinting |
| extension/src/content/native-picker/idb-seeder.ts | Seeds GitHub’s IndexedDB cache for first-open picker correctness |
| extension/src/content/native-picker/feed-shapes.ts | Shared payload/type definitions for feed augmentation and events |
| extension/src/content/issue-sidebar.ts | Removes custom picker wiring; adds membership hint support; hides card on issues |
| extension/src/content/global-boards-picker.ts | Deletes retired custom picker implementation |
| extension/manifest.json | Adds native-picker.js content script and native-picker-injector.js WAR entry |
| docs/global-boards-picker-status.md | Updates documentation to reflect native injection behavior and support matrix |
| docs/canonical-test-urls.md | Refreshes canonical URLs and scenario matrix for manual validation |
| CONTRIBUTING.md | Adds guidance for keeping Spec Kit integration files up to date |
| AGENT.md | Expands dev-Chrome/CDP verification workflow and adds worktree-testing notes |
| .specify/workflows/workflow-registry.json | Registers bundled Spec Kit workflow metadata |
| .specify/workflows/speckit/workflow.yml | Adds the multi-step Spec Kit “full SDD cycle” workflow definition |
| .specify/templates/tasks-template.md | Updates tasks template wording and command naming |
| .specify/templates/spec-template.md | Formatting/whitespace cleanups in spec template |
| .specify/templates/plan-template.md | Updates plan template references to dash-syntax commands |
| .specify/templates/checklist-template.md | Updates checklist template semantics and command naming |
| .specify/scripts/bash/setup-tasks.sh | New/updated helper to resolve task template and available docs |
| .specify/scripts/bash/setup-plan.sh | Updates plan setup behavior (skip overwrite; improved template resolution) |
| .specify/scripts/bash/resolve-template.sh | Adds template resolution helper for composed override stacks |
| .specify/scripts/bash/check-prerequisites.sh | Adds --template, --paths-only no-persist behavior, and improved parsing |
| .specify/integrations/speckit.manifest.json | Records installed Spec Kit integration assets/hashes |
| .specify/integrations/cursor-agent.manifest.json | Records Cursor agent skill files/hashes installed by Spec Kit |
| .specify/integrations/claude.manifest.json | Records Claude skill files/hashes installed by Spec Kit |
| .specify/integration.json | Records current default integration configuration |
| .specify/feature.json | Adds feature-directory pointer file (should be machine-local) |
| .specify/.gitignore | Gitignores Spec Kit machine-local state such as feature.json |
| .cursor/skills/speckit-taskstoissues/SKILL.md | Updates Cursor skill definition and workflow for tasks → issues |
| .cursor/skills/speckit-tasks/SKILL.md | Updates Cursor skill definition for tasks generation |
| .cursor/skills/speckit-plan/SKILL.md | Adds Cursor skill for planning workflow |
| .cursor/skills/speckit-implement/SKILL.md | Updates Cursor skill for implementation workflow |
| .cursor/skills/speckit-constitution/SKILL.md | Adds Cursor skill for constitution updates |
| .cursor/skills/speckit-checklist/SKILL.md | Updates Cursor skill for custom checklist generation |
| .cursor/skills/speckit-analyze/SKILL.md | Updates Cursor skill for cross-artifact analysis |
| .cursor/commands/speckit.taskstoissues.md | Removes deprecated Cursor command file (replaced by skills) |
| .cursor/commands/speckit.plan.md | Removes deprecated Cursor command file (replaced by skills) |
| .cursor/commands/speckit.constitution.md | Removes deprecated Cursor command file (replaced by skills) |
| .claude/skills/speckit-taskstoissues/SKILL.md | Adds/updates Claude skill definition for tasks → issues |
| .claude/skills/speckit-tasks/SKILL.md | Adds/updates Claude skill definition for tasks generation |
| .claude/skills/speckit-plan/SKILL.md | Adds Claude skill definition for planning workflow |
| .claude/skills/speckit-implement/SKILL.md | Adds/updates Claude skill definition for implementation workflow |
| .claude/skills/speckit-constitution/SKILL.md | Adds Claude skill definition for constitution updates |
| .claude/skills/speckit-checklist/SKILL.md | Adds/updates Claude skill definition for custom checklist generation |
| .claude/skills/speckit-analyze/SKILL.md | Adds/updates Claude skill definition for cross-artifact analysis |
| .claude/commands/speckit.taskstoissues.md | Removes deprecated Claude command file (replaced by skills) |
| .claude/commands/speckit.plan.md | Removes deprecated Claude command file (replaced by skills) |
| .claude/commands/speckit.constitution.md | Removes deprecated Claude command file (replaced by skills) |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| - Whether the repo lives in the **FilOzone** org (same org as the global FOC Projects v2 board). | ||
| - Whether the issue/PR is a **member of the global FOC project** on that board. | ||
| - Whether the issue/PR is a item is **on the global FOC board**. |
| ## V4: Member issue, read-only correctness (cross-org, member) | ||
|
|
||
| 1. Open `ipld/frisbii#170` (member; viewer may lack repo write access). | ||
| 2. Expect: if GitHub shows no picker (no write access), the extension adds none; membership remains visible via the FOC card as today. No false checked/unchecked flash anywhere (FR-010). |
Comment on lines
+1
to
+3
| { | ||
| "feature_directory": "specs/008-native-picker-data-injection" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the custom global-boards picker UI (spec 006) with data-layer interception, so GitHub renders everything itself. Configured global boards (canonically the FilOzone FOC board) appear and behave as native rows in GitHub's own Projects picker and Projects section on repos outside the board's org.
document_startmain-world injector augments the/_ghui/item-pickers/projectsfeed, seeds GitHub's IndexedDB picker cache for first-open correctness, and commits an enriched membership edge into the page's Relay store. Result: native picker row with correct checked state, native add AND remove via GitHub's own cookie-authenticated mutations (verified accepted cross-org), and a native project card in the Projects section with collapsed Status, expandable field list (fetched by GitHub itself), and native field editing.projects_suggestionsfeed augmentation; because GitHub's legacy toggle endpoint silently ignores cross-org ids, the extension intercepts the form POST and performs add/remove via its existing GraphQL path. The FOC field card remains on PR pages only (GitHub cannot render cross-org boards there) and stays in sync via a membership hint.FilOzone/*removed from the proactive defaults.global-boards-picker.ts, the custom dialog section / PR fourth tab, and their CSS (~370 lines deleted); the DOM-anchoring workarounds documented in github-page-layout.md go with them.Robustness measures (all fail-open to untouched native behavior)
ProjectItemSectionFieldListQuerypersisted-query hash (survives GitHub hash rotation; self-heals on any project card expansion).Manifest smoke checklist (constitution I/IV)
native-picker.jsatdocument_startmatchinghttps://github.com/*— wider than issue/PR patterns because Turbo soft-navigates from issue lists into issue pages in one JS context; justification in specs/008-native-picker-data-injection/plan.md. Loader is dormant off issue/PR pages.web_accessible_resourcesentry:native-picker-injector.js(main-world script, same pattern asboard-data-injector.js).Verification
Manual per quickstart (specs/008-native-picker-data-injection/quickstart.md, results recorded inside): V1-V8 pass on the canonical test URLs (docs/canonical-test-urls.md, refreshed in this PR: scenarios 4/6 now use BigLep/.github fixtures with write access; column renamed to "On FOC board"). All test mutations were reverted; board state is canonical.
npm run buildandnpm run typecheckclean.Docs updated: canonical terminology section and data-layer reference in docs/github-page-layout.md, support matrix and open-issues list in docs/global-boards-picker-status.md, full research trail in specs/008-native-picker-data-injection/.
🤖 Generated with Claude Code