Repository navigation
feat(website): one spec declares a site, composes it and checks any server (FD-4683) - #445
williamloo-scale wants to merge 1 commit into
Conversation
| elif key == "uses" and not at: | ||
| kept = {_use_id(u): u for u in merged.get("uses", [])} | ||
| kept.update({_use_id(u): copy.deepcopy(u) for u in value}) | ||
| merged["uses"] = list(kept.values()) |
There was a problem hiding this comment.
Mistyped specs crash validation
A file containing extends = "base.toml" and uses = 1 reaches this loop before _validated() and raises TypeError. An inherited data.collections = [1] in another folder similarly crashes _rebased() at .values().
The CLI and bundle authoring catch only SpecError, so authors get a traceback instead of an error naming the bad field. Check these types before merging and rebasing, or turn these failures into SpecError.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/agentenv-protocol/src/agentenv_protocol/website/spec/__init__.py
Line: 577-580
Comment:
**Mistyped specs crash validation**
A file containing `extends = "base.toml"` and `uses = 1` reaches this loop before `_validated()` and raises `TypeError`. An inherited `data.collections = [1]` in another folder similarly crashes `_rebased()` at `.values()`.
The CLI and bundle authoring catch only `SpecError`, so authors get a traceback instead of an error naming the bad field. Check these types before merging and rebasing, or turn these failures into `SpecError`.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| for key in ("session_cookie", "session_path", "state", "clock"): | ||
| if key in declared and site.get(key) != declared[key]: | ||
| problems.append(f"the card's {key} is {site.get(key)!r}, the spec's {declared[key]!r}") |
There was a problem hiding this comment.
_spec_card() accepts a cookie-based sign-in when the spec explicitly sets users.sign_in = "none". to_card_extension() omits the session fields for that spec, and this loop checks only fields that are present. Authors can therefore get a passing card check for a server with a different sign-in mode. Check that session fields are absent when the spec disables sign-in.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/agentenv-protocol/src/agentenv_protocol/website/conformance.py
Line: 331-333
Comment:
**Wrong sign-in mode passes**
`_spec_card()` accepts a cookie-based sign-in when the spec explicitly sets `users.sign_in = "none"`. `to_card_extension()` omits the session fields for that spec, and this loop checks only fields that are present. Authors can therefore get a passing card check for a server with a different sign-in mode. Check that session fields are absent when the spec disables sign-in.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.7368619 to
be46573
Compare
8090f3e to
2d64812
Compare
| raw["routes"] = {"ops": {r.name: {"method": r.method, "path": openapi_path(r.path), "roles": list(r.roles)} | ||
| for r in routes}} |
There was a problem hiding this comment.
Distinct routes prevent startup
from_environment() removes path converters before checking for duplicate routes. An existing class can serve /items/{id:int} first and /items/{id} second, under different route names, so numbers reach one handler and other values reach the other. Both paths now become /items/{id}, causing resolve() to raise SpecError while create_app() builds the card. The site no longer starts, even without spec=.
Preserve the distinction between these served routes when deriving the spec.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/agentenv-protocol/src/agentenv_protocol/website/spec/__init__.py
Line: 865-866
Comment:
**Distinct routes prevent startup**
`from_environment()` removes path converters before checking for duplicate routes. An existing class can serve `/items/{id:int}` first and `/items/{id}` second, under different route names, so numbers reach one handler and other values reach the other. Both paths now become `/items/{id}`, causing `resolve()` to raise `SpecError` while `create_app()` builds the card. The site no longer starts, even without `spec=`.
Preserve the distinction between these served routes when deriving the spec.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.…erver (FD-4683) This PR's change, rebased as one commit onto #444. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
be46573 to
90499de
Compare
2d64812 to
0ef31b9
Compare
| raw["routes"] = {"ops": {r.name: {"method": r.method, "path": openapi_path(r.path), "roles": list(r.roles)} | ||
| for r in routes}} |
There was a problem hiding this comment.
Existing route names prevent startup
An existing site with an @api name such as name="items:list" now fails during create_app(), even without spec=. @api accepts that name, but card creation now passes it through Routes._names, which rejects the colon and raises SpecError.
Preserve names accepted by existing decorators when deriving their specs.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/agentenv-protocol/src/agentenv_protocol/website/spec/__init__.py
Line: 865-866
Comment:
**Existing route names prevent startup**
An existing site with an `@api` name such as `name="items:list"` now fails during `create_app()`, even without `spec=`. `@api` accepts that name, but card creation now passes it through `Routes._names`, which rejects the colon and raises `SpecError`.
Preserve names accepted by existing decorators when deriving their specs.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Stacked on #444.
A website spec: one TOML file declares a site, composes from parts, and checks any server against it. Design:
docs/website-spec.md.agentenv_protocol.website.specreads[site],[source],[data],[users],[roles],[routes.ops],[state],[clock],[[uses]]andextends, with validation, overlays, composition, card params,from_card,from_environment, a JSON Schema and a CLI (validate,show,show --card).@website(spec="website.toml"): the class is refused when its@apiroutes aren't the spec's, and its card is built from the spec. Notes now declares itself this way.spec = "website.toml"or an inline[spec]; the env takes its name, health path and domains from it.conformance --specchecks a server's card and routes against the spec; those checks are required.examples/website/specs/: a replayed Slack overlay, an intranet, and an SSO component.Live and replay sources,
served_byandmodels = "mcp:..."are modelled in the spec but not deployable from env.toml yet.Test
Unit suite: 12,793 passed (one GitHub-clone test from main, which hangs on the local machine on main too, deselected).
🤖 Generated with Claude Code
Fix the startup failures for existing route names and distinct converter routes before merging.
Fix with agent prompt
Summary
Adds one website spec for loading, overlays, components, cards, bundle authoring and conformance checks. Notes now declares its site through
website.toml.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR TOML[Website TOML] --> Resolve[Resolve overlays and components] Resolve --> Spec[WebsiteSpec] Spec --> SDK[Check SDK class] SDK --> Card[Website card] Spec --> Bundle[Bundle name, health and domains] Spec --> Check[Conformance checks] Server[Running server] --> CheckReviews (10) · Last reviewed commit: "feat(website): one spec declares a site,..." · Reviewed by Greptile