GoogleCloudPlatform / GoogleCloudPlatform/knowledge-catalog

visualize: percent-encoded link targets are never decoded — bundles with spaces in filenames render with 0 edges

Open Beginner friendly
#200 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
9.2k
Forks
782
Avg merge
6h 36m
Merged PRs (30d)
85

Description

## Summary

`_extract_links` in `okf/src/reference_agent/viewer/generator.py` never percent-decodes link targets, so any cross-link whose target is percent-encoded — the only CommonMark-conformant way to link to a file whose name contains a space — fails to match its concept and produces **no edge**. A bundle whose filenames contain spaces therefore renders as a fully disconnected node cloud, even when every link is well-formed and every target exists.

This is distinct from #48 (absolute `/`-prefixed links being skipped): the two bugs compound, but applying the #48 fix alone (e.g. PR #184) still yields 0 edges for percent-encoded targets. It is also the consumer-side counterpart of #112 / PR #186, whose proposed SPEC §5.4 says consumers resolving against the filesystem SHOULD percent-decode before matching — the reference viewer currently doesn't.

## Repro (2 files)

`repro-bundle/concepts/Customer Orders.md`:

```markdown
---
type: Reference
title: Customer Orders
---
See [Join Key](/concepts/Join%20Key.md).
```

`repro-bundle/concepts/Join Key.md`:

```markdown
---
type: Reference
title: Join Key
---
Target concept.
```

```
python -m reference_agent visualize --bundle ./repro-bundle
```

Expected: 2 concepts, 1 edge. Actual: `Wrote 2 concept(s), 0 edge(s), …`

Varying only the link in `Customer Orders.md` (verified at d44368c):

| link in `Customer Orders.md` | edges | why |
|---|---|---|
| `[Join Key](Join%20Key.md)` | **0** | resolved as the literal path `Join%20Key.md`; derived id `Join%20Key` never matches the concept id `Join Key` |
| `[Join Key](/concepts/Join%20Key.md)` | **0** | skipped as absolute (#48) **and** not decoded |
| `[Join Key](Join Key.md)` | **0** | `_LINK_RE` forbids whitespace, so the link is never extracted |
| control: `[join-key](join-key.md)` (no spaces anywhere) | **1** | |

Row 2 stays at 0 even with PR #184's absolute-link resolution applied (verified by patching `_extract_links` accordingly): decoding is a separate, unaddressed step.

## Root cause

In `okf/src/reference_agent/viewer/generator.py`:

- `_extract_links` (L48–L66) resolves the raw regex match against the filesystem without `urllib.parse.unquote`, so a percent-encoded target is looked up as a literal path and the derived id can never match the concept id that `_walk_concepts` derives from the (decoded) filename.
- L54 `if "://" in target or target.startswith("/"): continue` additionally drops all absolute bundle-relative links — already tracked in #48, listed here only because the two together are what take a real bundle to zero.
- L12 `_LINK_RE = re.compile(r"\]\(([^)\s]+\.md)(?:#[A-Za-z0-9_\-]*)?\)")` cannot match a destination containing a raw space. Per CommonMark a destination with spaces must be wrapped in `<…>` or percent-encoded, so this is secondary — but the regex supports neither, leaving no working way at all to link to a file with a space in its name.

## Real-world impact

A 166-concept bundle using the SPEC §5.1-recommended absolute form with percent-encoded path segments (874 cross-links in total) renders with **0 edges** — the graph view degrades to an unconnected node cloud precisely for bundles that follow the spec's recommended link style.

## Suggested fix

Decode the target before resolving, alongside the absolute-link resolution from #48/#184:

```python
from urllib.parse import unquote

# in _extract_links:
target = unquote(m.group(1))
```

If PR #186's SPEC §5.4 lands, the reference viewer — as the format's reference consumer — should demonstrate exactly that behavior. A regression test in `okf/tests/test_viewer.py` (e.g. `test_percent_encoded_links_become_edges`, asserting 1 edge for the 2-file bundle above) would pin it.

Happy to send a PR if useful.

Contributor guide

Open the contributing guide

Research direction

Start with _extract_links in okf/src/reference_agent/viewer/generator.py and reproduce the two-file bundle using `python -m reference_agent visualize --bundle ./repro-bundle`. Add the regression coverage described in okf/tests/test_viewer.py, then verify that the percent-encoded target produces one edge for two concepts.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-visualization
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.