Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 35 additions & 34 deletions Issues.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,67 +117,68 @@ Manual testing is slowing down releases. An automated testing pipeline will incr

---

Issue 6 — Fix README typo in onboarding section
Issue 6 — App crashes on login

## Why
The onboarding instructions include a misspelled command that confuses new contributors.
Users report the app terminates when submitting valid credentials, blocking access to core features.

## Scope
- Correct the typo in the onboarding README section
- Verify the command matches the repo's actual script name
- Capture crash logs on login failure
- Identify the regression window
- Implement and verify the fix

## Tasks
- [ ] Locate the onboarding command in README
- [ ] Fix the typo and ensure formatting stays intact
- [ ] Reproduce crash on the login flow
- [ ] Inspect recent auth/session changes for regressions
- [ ] Add guardrails around null session handling
- [ ] Verify fix across supported platforms

## Acceptance Criteria
- Onboarding command is spelled correctly
- README formatting remains unchanged elsewhere
- Login no longer crashes on valid credentials
- Crash logs show no login-related stack traces
- Regression tests cover the login flow

---

Issue 7 — Integrate Stripe payments for subscriptions
Issue 7 — Add dark mode support

## Why
Recurring subscriptions are blocked until Stripe billing is integrated.
Users in low-light environments want a darker UI to reduce eye strain.

## Scope
- Add Stripe checkout flow for subscription tiers
- Store Stripe customer IDs for existing users

## Dependencies
- Stripe API access and test keys
- Webhook endpoint configuration in Stripe
- Provide a dark theme for core screens
- Respect OS-level theme preferences
- Add a manual toggle in settings

## Tasks
- [ ] Create Stripe customer records for new signups
- [ ] Implement subscription checkout session
- [ ] Handle Stripe webhook events for subscription status
- [ ] Design dark theme color palette
- [ ] Implement theme switcher logic
- [ ] Update core screens for dark mode
- [ ] Add settings toggle with persistence

## Acceptance Criteria
- Users can start a subscription via Stripe checkout
- Subscription status syncs via webhooks
- Billing events are recorded in the database
- Users can enable dark mode from settings
- OS theme preference is respected by default
- Core screens render correctly in dark mode

---

Issue 8 — Rotate GitHub secrets for CI
Issue 8 — Bug in docs examples

## Why
Security policy requires rotating CI secrets every 90 days.
Documentation examples currently fail when copied, leading to user confusion and support requests.

## Scope
- Rotate CI service account token
- Update secrets referenced by workflows

## Admin Access
- Requires org admin to update repository secrets
- Identify broken examples in docs
- Fix example code and outputs
- Add validation for docs snippets

## Tasks
- [ ] Rotate service account token in secret manager
- [ ] Update GitHub repository secrets with new token
- [ ] Confirm CI runs use updated secrets
- [ ] Audit docs examples for correctness
- [ ] Update broken examples and expected output
- [ ] Add a quick docs validation check

## Acceptance Criteria
- New token is active in GitHub secrets
- CI pipelines succeed with rotated credentials
- Docs examples run without errors
- Updated snippets match current API behavior
- Validation covers the critical docs examples
1 change: 1 addition & 0 deletions agents/codex-693.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- bootstrap for codex on issue #693 -->
67 changes: 0 additions & 67 deletions pr_body.md

This file was deleted.

Empty file modified scripts/issue_dedup_smoke.py
100644 → 100755
Empty file.
131 changes: 130 additions & 1 deletion scripts/langchain/label_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,64 @@ class LabelMatch:
DEFAULT_LABEL_SIMILARITY_THRESHOLD = 0.8
DEFAULT_LABEL_SIMILARITY_K = 5
SHORT_LABEL_LENGTH = 4
KEYWORD_BUG_SCORE = 0.91
KEYWORD_FEATURE_SCORE = 0.9
KEYWORD_DOCS_SCORE = 0.9
_IGNORED_LABEL_TOKENS = {"type", "kind"}
_BUG_KEYWORDS = {
"bug",
"bugs",
"buggy",
"crash",
"crashes",
"crashed",
"error",
"errors",
"failure",
"failures",
"broken",
"regression",
"defect",
}
_FEATURE_KEYWORDS = {
"feature",
"features",
"enhancement",
"enhancements",
"request",
"requests",
"improvement",
"improvements",
"support",
"add",
"enable",
}
_FEATURE_PHRASES = {
"dark mode",
"light mode",
}
_DOCS_KEYWORDS = {
"doc",
"docs",
"documentation",
"readme",
"guide",
"guides",
"example",
"examples",
"tutorial",
"tutorials",
}


def _normalize_label(name: str) -> str:
return re.sub(r"[^a-z0-9]+", "", name.lower())


def _tokenize(text: str) -> set[str]:
return set(re.findall(r"[a-z0-9]+", text.lower()))


def _coerce_label(item: Any) -> LabelRecord | None:
if isinstance(item, LabelRecord):
return item
Expand Down Expand Up @@ -152,6 +204,72 @@ def _exact_short_label_match(label_store: LabelVectorStore, query: str) -> Label
return None


def _token_matches_keyword(token: str, keyword: str) -> bool:
if token == keyword:
return True
if len(token) >= 4 and token.startswith(keyword):
return True
return bool(len(keyword) >= 4 and keyword.startswith(token))


def _keyword_match_score(label: LabelRecord, query: str) -> float | None:
tokens = _tokenize(query)
if not tokens:
return None

query_lower = query.lower()
label_text = " ".join(part for part in (label.name, label.description) if part)
label_tokens = _tokenize(label_text) - _IGNORED_LABEL_TOKENS
if label_tokens and label_tokens.intersection(tokens):
return 0.95

normalized = _normalize_label(label_text)
score = 0.0

if "bug" in normalized and any(
_token_matches_keyword(token, keyword) for token in tokens for keyword in _BUG_KEYWORDS
):
score = max(score, KEYWORD_BUG_SCORE)
if any(tag in normalized for tag in ("feature", "enhancement", "request")) and (
any(
_token_matches_keyword(token, keyword)
for token in tokens
for keyword in _FEATURE_KEYWORDS
)
or any(phrase in query_lower for phrase in _FEATURE_PHRASES)
):
score = max(score, KEYWORD_FEATURE_SCORE)
if "doc" in normalized and any(
_token_matches_keyword(token, keyword) for token in tokens for keyword in _DOCS_KEYWORDS
):
score = max(score, KEYWORD_DOCS_SCORE)

return score or None


def _keyword_matches(
labels: Iterable[LabelRecord],
query: str,
*,
threshold: float | None = None,
) -> list[LabelMatch]:
min_score = _resolve_threshold(threshold)
matches: list[LabelMatch] = []
for label in labels:
score = _keyword_match_score(label, query)
if score is None or score < min_score:
continue
matches.append(
LabelMatch(
label=label,
score=score,
raw_score=score,
score_type="keyword",
)
)
return matches


def find_similar_labels(
label_store: LabelVectorStore,
query: str,
Expand All @@ -170,7 +288,9 @@ def find_similar_labels(
search_fn = store.similarity_search_with_score
score_type = "distance"
else:
return []
matches = _keyword_matches(label_store.labels, query, threshold=threshold)
matches.sort(key=lambda match: match.score, reverse=True)
return matches

limit = k or DEFAULT_LABEL_SIMILARITY_K
try:
Expand All @@ -195,6 +315,15 @@ def find_similar_labels(
)
)

keyword_matches = _keyword_matches(label_store.labels, query, threshold=threshold)
if keyword_matches:
seen = {_normalize_label(match.label.name) for match in matches}
for match in keyword_matches:
normalized = _normalize_label(match.label.name)
if normalized and normalized not in seen:
matches.append(match)
seen.add(normalized)

matches.sort(key=lambda match: match.score, reverse=True)
return matches

Expand Down
Loading
Loading