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
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ LLM_GATEWAY_EMBEDDING_MODEL=
LLM_API_GATEWAY=
LLM_API_KEY=
CALDAV_BASE_URL=
# Optional Naruon calendar projection consume (ADR 0203 step 2 / #336).
# Empty keeps observed events fail-closed. Never put an end-user bearer here.
# CALDAV_BASE_URL is not a fallback for this audience.
NARUON_CALENDAR_BASE_URL=
NARUON_CALENDAR_SERVICE_TOKEN=
RANKWEAVE_DISABLED=

# Optional process HMAC for GET /api/ontology/neighborhood source continuation.
Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.d/2.17.0-naruon-calendar-buyer-wiring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 2.17.0 — Wire the Naruon calendar projection into the Buyer Calendar

## Added

- `GET /api/calendar` now consumes the Naruon calendar projection (ADR 0203
step 2 / #336) beside post-grounded commitments. Observed occurrences stay
non-clickable evidence; a commitment still opens that post.
- `WorkspaceCalendar` is the 달력 destination and Storybook catalog entry.
Fail-closed copy remains `이 범위의 일정을 아직 받을 수 없습니다`.

## Changed

- Product copy no longer names a custom JSON feed as CalDAV. Missing or
malformed `NARUON_CALENDAR_BASE_URL` / `NARUON_CALENDAR_SERVICE_TOKEN`
keeps events empty and commitments available. `CALDAV_BASE_URL` is not a
fallback.

## Security

- The end-user bearer token is never forwarded to Naruon. Observed events
carry no `post_id` or `issue_ticket_id` and are never promoted into tickets.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ All notable changes to this project are documented here. Format follows

### Added

- Buyer Calendar now consumes the Naruon calendar projection beside
post-grounded commitments (ADR 0203 step 2 / #336). Observed occurrences
stay evidence-only; a commitment still opens that post. The 달력
destination fail-closes with `이 범위의 일정을 아직 받을 수 없습니다`
when the Naruon audience is missing. `CALDAV_BASE_URL` is not a fallback.

- Registered the `analysis_run_topic_lineage` analysis-run kind (migrations
0131/0132, ADR 0132), the LineageWeave-side consumption boundary for
TEPP's Temporal Relational Shared-Latent Topic Measurement (TRSL-TM,
Expand Down
6 changes: 6 additions & 0 deletions backend/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class Settings:
tepp_transport_url: str
tepp_api_key: str
caldav_base_url: str
naruon_calendar_base_url: str
naruon_calendar_service_token: str
rankweave_disabled: bool
ontology_source_cursor_secret: str

Expand Down Expand Up @@ -172,6 +174,10 @@ def load_settings() -> Settings:
tepp_transport_url=os.environ.get("TEPP_TRANSPORT_URL", ""),
tepp_api_key=os.environ.get("TEPP_API_KEY", ""),
caldav_base_url=os.environ.get("CALDAV_BASE_URL", "").strip(),
naruon_calendar_base_url=os.environ.get("NARUON_CALENDAR_BASE_URL", "").strip(),
naruon_calendar_service_token=os.environ.get(
"NARUON_CALENDAR_SERVICE_TOKEN", ""
).strip(),
rankweave_disabled=os.environ.get("RANKWEAVE_DISABLED", "")
.strip()
.lower()
Expand Down
53 changes: 31 additions & 22 deletions backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import logging
from contextlib import asynccontextmanager
from dataclasses import asdict
from datetime import datetime
from datetime import datetime, timezone
from typing import Any, Literal
from uuid import UUID

Expand All @@ -42,10 +42,6 @@
ContextualOrchestratorCommitmentExtractionClient,
NullCommitmentExtractionClient,
)
from lineageweave.caldav_client import (
CALDAV_UNAVAILABLE_NEXT_ACTION,
build_caldav_client,
)
from lineageweave.entity_relationship_classification import (
ContextualOrchestratorEntityRelationshipClient,
NullEntityRelationshipClient,
Expand Down Expand Up @@ -93,6 +89,11 @@
from lineageweave.semantic_hints import customer_hint_trust, format_semantic_hints
from lineageweave.ontology import LW
from lineageweave.rankweave_client import build_rankweave_client
from lineageweave.naruon_calendar_workspace import (
build_workspace_naruon_client,
default_calendar_window,
load_observed_calendar_events,
)

from backend.app.analysis_run_ingestion import (
AnalysisRunCreateError,
Expand Down Expand Up @@ -3371,25 +3372,33 @@ async def read_analysis_run(
async def read_calendar(
account: CurrentAccount = Depends(get_current_account),
pool: asyncpg.Pool = Depends(get_pool),
window_start: str | None = Query(default=None),
window_end: str | None = Query(default=None),
) -> dict[str, Any]:
"""Return independent CalDAV events alongside authorized commitments.
"""Return Naruon observed events beside authorized commitments.

An unavailable optional CalDAV source never hides the internal to-do
projection and never creates a synthetic event.
A missing or malformed Naruon audience never hides the internal to-do
projection and never creates a synthetic event. The end-user bearer
token is not forwarded.
"""
_require_post_read(account)
caldav = build_caldav_client(load_settings().caldav_base_url)
events = []
caldav_available = caldav.available
caldav_next_action = None
if caldav.available:
try:
events = [asdict(event) for event in caldav.list_events()]
except (HttpClientError, OSError, ValueError):
caldav_available = False
caldav_next_action = CALDAV_UNAVAILABLE_NEXT_ACTION
else:
caldav_next_action = CALDAV_UNAVAILABLE_NEXT_ACTION
if (window_start is None) ^ (window_end is None):
raise HTTPException(
status.HTTP_422_UNPROCESSABLE_ENTITY,
"window_start and window_end must be supplied together",
)
settings = load_settings()
if window_start is None or window_end is None:
window_start, window_end = default_calendar_window(datetime.now(timezone.utc))
naruon = load_observed_calendar_events(
build_workspace_naruon_client(
settings.naruon_calendar_base_url,
settings.naruon_calendar_service_token,
),
window_start,
window_end,
)
Comment thread
seonghobae marked this conversation as resolved.
Comment thread
seonghobae marked this conversation as resolved.
events = [asdict(event) for event in naruon.events]
async with pool.acquire() as conn:
commitments = await fetch_upcoming_commitments(conn)
demo_entity_ids: set[str] = set()
Expand All @@ -3408,8 +3417,8 @@ async def read_calendar(
"events": events,
"commitments": visible,
"calendar_sources": {
"caldav_available": caldav_available,
"caldav_next_action": caldav_next_action,
"naruon_available": naruon.available,
"naruon_next_action": naruon.next_action,
},
}

Expand Down
31 changes: 30 additions & 1 deletion backend/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4691,7 +4691,36 @@ def test_derive_commitment_requires_post_admin(client, demo_analyst_token, seede
def test_calendar_is_empty_before_any_commitment(client, demo_analyst_token, seeded_db) -> None:
response = client.get("/api/calendar", headers={"Authorization": f"Bearer {demo_analyst_token}"})
assert response.status_code == 200
assert response.json()["commitments"] == []
payload = response.json()
assert payload["commitments"] == []
assert payload["events"] == []
assert payload["calendar_sources"]["naruon_available"] is False
assert "Connect the Naruon calendar projection" in payload["calendar_sources"]["naruon_next_action"]
assert "caldav_available" not in payload["calendar_sources"]


def test_calendar_window_requires_both_bounds(client, demo_analyst_token, seeded_db) -> None:
response = client.get(
"/api/calendar",
params={"window_start": "2026-08-25T00:00:00Z"},
headers={"Authorization": f"Bearer {demo_analyst_token}"},
)
assert response.status_code == 422
assert "together" in response.json()["detail"]


def test_calendar_does_not_treat_caldav_url_as_naruon(
client, demo_analyst_token, seeded_db, monkeypatch
) -> None:
monkeypatch.setenv("CALDAV_BASE_URL", "https://calendar.example/caldav/")
monkeypatch.delenv("NARUON_CALENDAR_BASE_URL", raising=False)
monkeypatch.delenv("NARUON_CALENDAR_SERVICE_TOKEN", raising=False)
response = client.get("/api/calendar", headers={"Authorization": f"Bearer {demo_analyst_token}"})
assert response.status_code == 200
payload = response.json()
assert payload["events"] == []
assert payload["calendar_sources"]["naruon_available"] is False
assert "caldav_available" not in payload["calendar_sources"]


def test_calendar_hides_other_corp_private_commitments_and_sorts_by_due_date(
Expand Down
17 changes: 17 additions & 0 deletions backend/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ def test_local_keycloak_discovery_uses_backend_reachable_base_url(monkeypatch) -
)


def test_naruon_calendar_audience_defaults_empty_and_is_not_caldav(monkeypatch) -> None:
"""Missing Naruon settings keep the observed-event channel dropped."""
monkeypatch.delenv("NARUON_CALENDAR_BASE_URL", raising=False)
monkeypatch.delenv("NARUON_CALENDAR_SERVICE_TOKEN", raising=False)
monkeypatch.setenv("CALDAV_BASE_URL", "https://calendar.example/caldav/")
settings = load_settings()
assert settings.naruon_calendar_base_url == ""
assert settings.naruon_calendar_service_token == ""
assert settings.caldav_base_url == "https://calendar.example/caldav/"
monkeypatch.setenv("NARUON_CALENDAR_BASE_URL", "https://naruon.example/projection")
monkeypatch.setenv("NARUON_CALENDAR_SERVICE_TOKEN", "service-secret")
wired = load_settings()
assert wired.naruon_calendar_base_url == "https://naruon.example/projection"
assert wired.naruon_calendar_service_token == "service-secret"
assert wired.naruon_calendar_service_token != wired.caldav_base_url


def test_rankweave_disabled_defaults_off(monkeypatch) -> None:
monkeypatch.delenv("RANKWEAVE_DISABLED", raising=False)
assert load_settings().rankweave_disabled is False
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ services:
TEPP_TRANSPORT_URL: ${TEPP_TRANSPORT_URL:-}
TEPP_API_KEY: ${TEPP_API_KEY:-}
CALDAV_BASE_URL: ${CALDAV_BASE_URL:-}
NARUON_CALENDAR_BASE_URL: ${NARUON_CALENDAR_BASE_URL:-}
NARUON_CALENDAR_SERVICE_TOKEN: ${NARUON_CALENDAR_SERVICE_TOKEN:-}
RANKWEAVE_DISABLED: ${RANKWEAVE_DISABLED:-}
# Process HMAC for ontology source-window continuation. Empty keeps the
# truncated-without-cursor contract. Never reuse an OIDC or orchestrator secret.
Expand Down
11 changes: 7 additions & 4 deletions docs/adr/0183-gnb-four-korean-chrome.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
Main still shipped `BuyerNav` with English analyst tabs (Board / Customer
master / Calendar / Ask Agent / Admin). LineageWeave is an analyst workspace,
not a storefront, so "Buyer" and "Cubee" are not product names. Calendar is
CalendarWeave / Naruon CalDAV consume only (issue #336); this slice must not
add a calendar kernel.
CalendarWeave / Naruon consume only (issue #336); this slice must not
add a calendar kernel. v2.17.0 wires the 달력 destination to the Naruon
projection consume helper and keeps the same fail-closed copy.

## Decision

Expand All @@ -29,16 +30,18 @@ add a calendar kernel.
3. Operator Admin remains a non-GNB destination. It is not a fifth analyst tab.
4. Weekly VOC remains a board filter. Weekly/monthly newspaper remains a
scheduled board post. Neither is a GNB item.
5. The 달력 destination fail-closes when CalendarWeave / Naruon consume is
5. The 달력 destination fail-closes when Naruon calendar projection consume is
unwired or missing, with the exact copy
`이 범위의 일정을 아직 받을 수 없습니다`. Existing advanced-review
commitment projection is not a calendar kernel and is not this GNB surface.
Observed Naruon occurrences stay separate from post-grounded commitments.

## Consequences

- Analyst chrome no longer shows Buyer, Cubee, Board, or Customer master.
- CalendarWeave wiring stays a later consume-only slice. This PR does not
import naruon mailbox, ThreadWeave, or Keyverse dumps.
import naruon mailbox, ThreadWeave, or Keyverse dumps. v2.17.0 only
activates the published calendar projection consume path.
- Historical ADRs keep the wording of their time.

## References
Expand Down
10 changes: 10 additions & 0 deletions docs/adr/0203-naruon-calendar-projection-boundary.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ Until Naruon ships the matching read endpoint and service-audience contract,
LineageWeave runtime wiring remains disabled and fail-closed. Existing internal
commitments remain available even when the external event channel is absent.

LineageWeave v2.17.0 implements activation gate step 2: `GET /api/calendar`
and the 달력 destination consume `NARUON_CALENDAR_BASE_URL` /
`NARUON_CALENDAR_SERVICE_TOKEN` through
`lineageweave.naruon_calendar_workspace`. A missing audience, malformed
token, transport failure, or contract rejection returns `events: []` with
`naruon_available: false` and never invents an occurrence. Steps 3–5
(provider/consumer fixtures against a released Naruon artifact, degraded
behavior, and protected merge) remain open. Do not treat this wiring as a
completed Naruon connector.

## Consequences

### Positive
Expand Down
6 changes: 3 additions & 3 deletions docs/product-technical-gap-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ this file per §3.5 of the prior snapshot).
| #280 | Full project-lifecycle history and handover intervals | Tracked with issue #284; no active delivery PR confirmed |
| #284 | Authoritative lifecycle ingestion and idempotent reconciliation | No active delivery PR confirmed |
| #289 | Activate the optional lineage LLM channel through a bounded asynchronous rebuild | #434 |
| #336 | Replace pseudo-CalDAV feed with a Naruon-owned calendar projection | #355 |
| #336 | Replace pseudo-CalDAV feed with a Naruon-owned calendar projection | Contract on `main` (#355); Buyer consume wiring in `feat/naruon-calendar-buyer-wiring-v2170` |
| #338 | Evidence-bounded email/project lineage contract for Naruon consumption | #355 |
| #341 | Heterogeneous ontology and provenance explorer separate from Event Lineage | #349 |
| #358 | Batch reauthorize persisted post-Ask evidence without N+1 queries | Ask stack |
Expand All @@ -273,7 +273,7 @@ this file per §3.5 of the prior snapshot).
| Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence |
| Knowledge Graph readability | The black evidence-node root cause is an undefined-token fallback; the design-token repair and long-label/evidence-table coverage are present on #490, not protected `main` | Deliver the token repair through protected `main`, then verify light/dark contrast, keyboard graph navigation, full labels, and evidence tables in the authenticated rendered surface |
| Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding |
| Calendar / Naruon | #355 delivered the Naruon-owned projection contract and conformance fixture to protected `main`; live consumer acceptance is not yet evidenced | Verify Naruon consumption against the published schema and issues #336/#338 without invented events |
| Calendar / Naruon | #355 delivered the projection contract; v2.17.0 wires Buyer consume without forwarding the end-user token. Naruon producer, provider/consumer fixtures, and protected merge remain open (#336) | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired |
| SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound |
| Event Lineage evidence | Channel evidence and Allen relations live on #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score |
| Scientific measurement | Durable accepted TEPP receipts and fail-closed production weighting are protected (`main`); #468 binds fast-mlsirm/Keyverse/orchestrator/TEPP integration tests and now fails closed on upstream probability-axis drift. #387 removes inferred/default persistence weights and converts its 3/4-channel evidence tests to fast-mlsirm estimates, but several older reconstruction tests still pass hand-authored numeric weight dictionaries; those constants are not estimator evidence | Continue replacing remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures; tests unrelated to fusion must bypass weighting entirely, as #484 does. Land #387/#468/#417 through the standard gate and retain true-parameter RMSE recovery as the acceptance bar |
Expand Down Expand Up @@ -387,7 +387,7 @@ review latency are never blockers — keep working while they settle.
- Orchestrator / paper-grounded models: ADR 0015, ADR 0076 (Fugu, TRINITY, Conductor)
- Ontology / PROV-O / SKOS: ADR 0004, ADR 0011, issue #372
- Analysis runs / TEPP: ADR 0013–0023, issue #79 / #277
- Calendar / Naruon: issues #336 / #338, PR #355
- Calendar / Naruon: issues #336 / #338, PR #355, Buyer consume v2.17.0
- Ask Agent: issues #269–#272, #358–#363

Citations in doctoring and ADRs use APA 7th. Do not invent a heuristic where
Expand Down
2 changes: 1 addition & 1 deletion docs/storybook-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buyer-facing control you can click before changing product CSS.
| `Evidence/OrganizationAliasChip` | Click a cataloged org; the parenthetical is the unique corroborated SKOS companion. | `--color-chip-border`, `--radius-chip`, `OrganizationAliasChip` |
| `AnalysisRun/CutoffKnownBody` | Read the cutoff-known sentence, then compare it with the live body below. | `--color-accent-border`, `--space-panel-block`, `--radius-panel`, `CutoffKnownBody` |
| `Analysis/LineageEntityPicker` | Choose which corp to reconstruct, then click Request a lineage reconstruction. | `--space-control-gap`, `--size-control-min`, `--radius-control`, `LineageEntityPicker` |
| `Chrome/PopupCloseButton` | Close the evidence panel or post popup. | `--space-close-inset`, `--font-size-close`, `PopupCloseButton` |
| `Workspace/WorkspaceCalendar` | Read observed Naruon events, or open a commitment to land on that post. Fail-closed copy stays `이 범위의 일정을 아직 받을 수 없습니다`. | `--color-chip-border`, `WorkspaceCalendar`, `EvidenceStatusMark` |
Comment thread
seonghobae marked this conversation as resolved.

Repeated web objects must use `frontend/src/styles/tokens.css` and a module
under `frontend/src/components/`. Do not add a second Node package manager;
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "2.15.1",
"version": "2.17.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
const button = screen.getByRole("button", { name: /log in/i });
await userEvent.click(button);
expect(signinRedirect).toHaveBeenCalledTimes(1);
expect(signinRedirect).toHaveBeenCalledWith(

Check failure on line 45 in frontend/src/App.test.tsx

View workflow job for this annotation

GitHub Actions / Frontend lint, test, build

src/App.test.tsx > App, unauthenticated > shows a login button that starts the real OIDC redirect

AssertionError: expected "vi.fn()" to be called with arguments: [ ObjectContaining{…} ] Received: 1st vi.fn() call: [ - ObjectContaining { + { "state": { - "returnUrl": "/?post=abc#evidence", + "returnUrl": "/?post=abc", }, }, ] Number of calls: 1 ❯ src/App.test.tsx:45:28
expect.objectContaining({
state: { returnUrl: "/?post=abc#evidence" },
}),
Expand Down Expand Up @@ -773,6 +773,7 @@
if (url.endsWith("/api/calendar")) {
return Promise.resolve(
jsonResponse({
events: [],
commitments:
options?.calendarCommitments ?? [
{
Expand Down Expand Up @@ -802,6 +803,11 @@
post_title: "Specification revision requested",
},
],
calendar_sources: {
naruon_available: false,
naruon_next_action:
"Connect the Naruon calendar projection. Open a commitment below to read that post.",
},
}),
);
}
Expand Down Expand Up @@ -2209,7 +2215,7 @@

await userEvent.type(within(board).getByLabelText("Search semantic evidence"), "not found");
await userEvent.click(within(board).getByRole("button", { name: "Search" }));
expect(within(board).getByRole("status")).toHaveTextContent("No posts match the current filters.");

Check failure on line 2218 in frontend/src/App.test.tsx

View workflow job for this annotation

GitHub Actions / Frontend lint, test, build

src/App.test.tsx > App, authenticated > renders the board landmark and functional post controls

TestingLibraryElementError: Found multiple elements with the role "status" Here are the matching elements: Ignored nodes: comments, script, style <p class="board-empty" role="status" > No posts match the current filters. </p> Ignored nodes: comments, script, style <p class="popup-placeholder" role="status" > 이 범위의 일정을 아직 받을 수 없습니다 </p> (If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)). Ignored nodes: comments, script, style <section aria-labelledby="board-title" class="board-surface" > <header class="board-header" > <div> <p class="post-meta" > Board </p> <h2 id="board-title" > Board </h2> <p> Authorized posts in this board. </p> </div> <p aria-live="polite" class="board-result-count" > Posts shown: 0 / 0 </p> </header> <form aria-label="Search and filter posts" class="board-controls" role="search" > <label> Search semantic evidence <input aria-label="Search semantic evidence" placeholder="Search semantic evidence" type="search" value="not found" /> </label> <button type="submit" > Search </button> <p class="board-search-help post-meta" > Search includes post text and semantic evidence. </p> <fieldset class="board-voc-type-filter" > <legend> Filter by VOC type </legend> </fieldset> <label> Filter by visibility <select aria-label="Filter by visibility" > <option value="all" > All visibility </option> </select> </label> <label> Sort posts <select aria-label="Sort posts" > <option value="newest" > Newest first </option> <option value="oldest" > Oldest first </option> <option value="title" > Title A-Z </option> </select> </label> <button class="board-reset" type="reset" > Reset filters </button> </form> <p class="board-empty" role="status" > No posts match the current filters. </p> <details class="advanced-review-tools" > <summary> Advanced review tools </summary> <section aria-labelledby="lab-calendar-heading" class="popup-section lineage-home" > <h2 id="lab-calendar-heading" > Calendar </h2> <section aria-labelledby="lab-calendar-heading-observed" class="popup-section" > <h3 id="lab-calendar-heading-observed" > Observed calendar events </h3> <p class="popup-placeholder" role="status" > 이 범위의 일정을 아직 받을 수 없습니다 </p> <p class="popup-placeholder" > Connect the Naruon calendar projection. Open a commitment below to read that post. </p> </section> <section aria-labelledby="lab-calendar-heading-commitments" class="popup-section" > <h3 id="lab-calendar-heading-commitments" > Upcoming commitments </h3> <ul class="ticket-list" > <li class="ticket-list-item" > <button aria-label="Open commitment for: Public post" class="post-list-item" type="button" > <span class="ticket-title" > Send Northridge Grid the revised quote </span> <span class="post-badge" > Public post </span
await userEvent.click(within(board).getByRole("button", { name: "Reset filters" }));
expect(within(board).getByRole("button", { name: "View post: Public post" })).toBeInTheDocument();
});
Expand Down Expand Up @@ -3360,7 +3366,7 @@
expect(
screen.getByRole("button", { name: "Compare Business unit (PU): Demo Report High, mean θ 0.81" }),
).not.toHaveAttribute("aria-current");
expect(screen.getByRole("status")).toHaveTextContent(

Check failure on line 3369 in frontend/src/App.test.tsx

View workflow job for this annotation

GitHub Actions / Frontend lint, test, build

src/App.test.tsx > App, authenticated > does not tell a succeeded period report to rebuild, reconstruct, or measure

TestingLibraryElementError: Found multiple elements with the role "status" Here are the matching elements: Ignored nodes: comments, script, style <p class="popup-placeholder" role="status" > 이 범위의 일정을 아직 받을 수 없습니다 </p> Ignored nodes: comments, script, style <p class="post-meta" role="status" > Demo Corp is the opened grouping. Read its mean θ and member posts below, then open a post. </p> (If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)). Ignored nodes: comments, script, style <body> <div> <div class="app-shell" > <header class="app-header" > <div class="app-header-logo" > <h1 class="app-header-title" > LineageWeave </h1> </div> <div class="app-header-top-menu" > <span class="app-user-profile" > demo.analyst </span> <button class="btn-secondary" > Log out </button> </div> </header> <nav aria-label="Workspace navigation" class="workspace-gnb" > <button aria-current="page" class="workspace-gnb-item" type="button" > 게시판 </button> <button class="workspace-gnb-item" type="button" > 고객 마스터 </button> <button class="workspace-gnb-item" type="button" > 달력 </button> <button class="workspace-gnb-item" type="button" > Ask Agent </button> <div class="workspace-gnb-tools" > <label class="language-switcher" > <span class="visually-hidden" > Language </span> <select aria-label="Language" > <option value="en" > English </option> <option value="ko" > 한국어 </option> <option value="zh" > 中文 </option> <option value="ja" > 日本語 </option> <option value="vi" > Tiếng Việt </option> </select> </label> </div> </nav> <main> <section aria-labelledby="board-title" class="board-surface" > <header class="board-header" > <div> <p class="post-meta" > Board </p> <h2 id="board-title" > Board </h2> <p> Authorized posts in this board. </p> </div> <p aria-live="polite" class="board-result-count" > Posts shown: 1 / 1 </p> </header> <form aria-label="Search and filter posts" class="board-controls" role="search" > <label> Search semantic evidence <input aria-label="Search semantic evidence" placeholder="Search semantic evidence" type="search" value="" /> </label> <button type="submit" > Search </button> <p class="board-search-
"Demo Corp is the opened grouping. Read its mean θ and member posts below, then open a post.",
);
expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument();
Expand Down Expand Up @@ -3407,7 +3413,7 @@
expect(demoChip).toHaveAccessibleName(/mean θ 0\.42/);
expect(scrollIntoView).toHaveBeenCalled();
expect(periodInput).not.toHaveFocus();
expect(screen.getByRole("status")).toHaveTextContent(

Check failure on line 3416 in frontend/src/App.test.tsx

View workflow job for this annotation

GitHub Actions / Frontend lint, test, build

src/App.test.tsx > App, authenticated > lands the comparison strip on Demo Corp when already on that week

TestingLibraryElementError: Found multiple elements with the role "status" Here are the matching elements: Ignored nodes: comments, script, style <p class="popup-placeholder" role="status" > 이 범위의 일정을 아직 받을 수 없습니다 </p> Ignored nodes: comments, script, style <p class="post-meta" role="status" > Demo Corp is the opened grouping. Read its mean θ and member posts below, then open a post. </p> (If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)). Ignored nodes: comments, script, style <body> <div> <div class="app-shell" > <header class="app-header" > <div class="app-header-logo" > <h1 class="app-header-title" > LineageWeave </h1> </div> <div class="app-header-top-menu" > <span class="app-user-profile" > demo.analyst </span> <button class="btn-secondary" > Log out </button> </div> </header> <nav aria-label="Workspace navigation" class="workspace-gnb" > <button aria-current="page" class="workspace-gnb-item" type="button" > 게시판 </button> <button class="workspace-gnb-item" type="button" > 고객 마스터 </button> <button class="workspace-gnb-item" type="button" > 달력 </button> <button class="workspace-gnb-item" type="button" > Ask Agent </button> <div class="workspace-gnb-tools" > <label class="language-switcher" > <span class="visually-hidden" > Language </span> <select aria-label="Language" > <option value="en" > English </option> <option value="ko" > 한국어 </option> <option value="zh" > 中文 </option> <option value="ja" > 日本語 </option> <option value="vi" > Tiếng Việt </option> </select> </label> </div> </nav> <main> <section aria-labelledby="board-title" class="board-surface" > <header class="board-header" > <div> <p class="post-meta" > Board </p> <h2 id="board-title" > Board </h2> <p> Authorized posts in this board. </p> </div> <p aria-live="polite" class="board-result-count" > Posts shown: 1 / 1 </p> </header> <form aria-label="Search and filter posts" class="board-controls" role="search" > <label> Search semantic evidence <input aria-label="Search semantic evidence" placeholder="Search semantic evidence" type="search" value="" /> </label> <button type="submit" > Search </button> <p class="board-search-
"Demo Corp is the opened grouping. Read its mean θ and member posts below, then open a post.",
);
expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument();
Expand Down Expand Up @@ -3913,7 +3919,7 @@
await userEvent.click(
screen.getByRole("button", { name: "Compare Thread group: A-100, mean θ 0.81" }),
);
expect(screen.getByRole("status")).toHaveTextContent(

Check failure on line 3922 in frontend/src/App.test.tsx

View workflow job for this annotation

GitHub Actions / Frontend lint, test, build

src/App.test.tsx > App, authenticated > shows the grouping comparison strip and switches grouping on click

TestingLibraryElementError: Found multiple elements with the role "status" Here are the matching elements: Ignored nodes: comments, script, style <p class="popup-placeholder" role="status" > 이 범위의 일정을 아직 받을 수 없습니다 </p> Ignored nodes: comments, script, style <p class="post-meta" role="status" > A-100 is the opened grouping. Read its mean θ and member posts below, then open a post. </p> (If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)). Ignored nodes: comments, script, style <body> <div> <div class="app-shell" > <header class="app-header" > <div class="app-header-logo" > <h1 class="app-header-title" > LineageWeave </h1> </div> <div class="app-header-top-menu" > <span class="app-user-profile" > demo.analyst </span> <button class="btn-secondary" > Log out </button> </div> </header> <nav aria-label="Workspace navigation" class="workspace-gnb" > <button aria-current="page" class="workspace-gnb-item" type="button" > 게시판 </button> <button class="workspace-gnb-item" type="button" > 고객 마스터 </button> <button class="workspace-gnb-item" type="button" > 달력 </button> <button class="workspace-gnb-item" type="button" > Ask Agent </button> <div class="workspace-gnb-tools" > <label class="language-switcher" > <span class="visually-hidden" > Language </span> <select aria-label="Language" > <option value="en" > English </option> <option value="ko" > 한국어 </option> <option value="zh" > 中文 </option> <option value="ja" > 日本語 </option> <option value="vi" > Tiếng Việt </option> </select> </label> </div> </nav> <main> <section aria-labelledby="board-title" class="board-surface" > <header class="board-header" > <div> <p class="post-meta" > Board </p> <h2 id="board-title" > Board </h2> <p> Authorized posts in this board. </p> </div> <p aria-live="polite" class="board-result-count" > Posts shown: 1 / 1 </p> </header> <form aria-label="Search and filter posts" class="board-controls" role="search" > <label> Search semantic evidence <input aria-label="Search semantic evidence" placeholder="Search semantic evidence" type="search" value="" /> </label> <button type="submit" > Search </button> <p class="board-search-help
"A-100 is the opened grouping. Read its mean θ and member posts below, then open a post.",
);
expect(
Expand Down Expand Up @@ -4086,13 +4092,22 @@
expect(screen.queryByText("Advanced review tools")).not.toBeInTheDocument();
});

it("fails closed on the calendar destination when CalendarWeave consume is unwired", async () => {
it("fails closed on the calendar destination when Naruon consume is unwired", async () => {
stubBackend();
render(<App />);

await userEvent.click(await screen.findByRole("button", { name: "달력" }));
expect(screen.getByRole("heading", { name: "달력" })).toBeInTheDocument();
expect(screen.getByText("이 범위의 일정을 아직 받을 수 없습니다")).toBeInTheDocument();
expect(screen.getByRole("heading", { name: "Observed calendar events" })).toBeInTheDocument();
expect(screen.queryByText(/CalDAV/i)).not.toBeInTheDocument();
expect(screen.queryByText(/Buyer|Cubee/i)).not.toBeInTheDocument();
await userEvent.click(
screen.getByRole("button", { name: /open commitment for: public post/i }),
);
expect(await screen.findByRole("button", { name: "게시판" })).toHaveAttribute(
"aria-current",
"page",
);
});
});
Loading
Loading