Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
fcc0813
[chore]: init project
jiaoew1991 Oct 26, 2025
180ae4e
[feat][aether] support as lance namespace
jiaoew1991 Oct 27, 2025
b3374b3
feat: setup ci (#2)
jiaoew1991 Oct 27, 2025
a65ba67
feat: add ci for cleanup old branches (#3)
jiaoew1991 Oct 27, 2025
7a65a03
feat: add raydp (#4)
jiaoew1991 Oct 27, 2025
c77eb74
feat: add iceberg catalog implements (#7)
jiaoew1991 Nov 3, 2025
7b40427
feat: init solstice (#18)
jiaoew1991 Nov 10, 2025
9aecbe4
refactor: iceberg catalog normalized (#19)
jiaoew1991 Nov 11, 2025
eca71a9
refactor: solstice with new end_to_end
jiaoew1991 Nov 12, 2025
09f7dc9
fix: ci (#20)
jiaoew1991 Nov 13, 2025
98b1ee1
feat: optimize recover logic, change state from worker_id to split_id…
jiaoew1991 Nov 13, 2025
94c5996
feat: new context and pipeline execution logic (#22)
jiaoew1991 Nov 17, 2025
46914eb
test: add integration test which is cut video (#23)
jiaoew1991 Nov 23, 2025
21ec9e6
test: fix test_video_workflow (#24)
jiaoew1991 Nov 26, 2025
e8420d5
feat: add k8s + rayjob manager for aether (#30)
jiaoew1991 Nov 26, 2025
37c3e70
test: use testcontainer to test aether (#31)
jiaoew1991 Nov 26, 2025
e80db10
fix: ci (#32)
jiaoew1991 Nov 27, 2025
f109c8d
chore: deploy aether in prod env (#33)
jiaoew1991 Nov 29, 2025
bc42b19
refactor: change operator config from dict to dataclass (#34)
jiaoew1991 Nov 29, 2025
a55d685
feat: support spark as source (#35)
jiaoew1991 Dec 1, 2025
43b593d
test: make video_slice_workflow works
jiaoew1991 Dec 3, 2025
052c555
fix: ci failed (#37)
jiaoew1991 Dec 3, 2025
9637802
chore: redesign checkpoint logic, it works now (#38)
jiaoew1991 Dec 5, 2025
dbb04c2
feat: change arch from push to pull (#39)
jiaoew1991 Dec 8, 2025
e3fdfab
feat: enhance development dependencies and CI workflow (#40)
jiaoew1991 Dec 9, 2025
88fcc69
feat: initial version of auto scaler (#48)
jiaoew1991 Dec 10, 2025
dd47fba
chore: optimize raySplitPayloadStore to avoid ser&deser twice
jiaoew1991 Dec 10, 2025
2acb432
docs: add Spark Source V2 design document (#51)
jiaoew1991 Dec 10, 2025
ba0b5df
docs: add agents.md (#53)
jiaoew1991 Dec 10, 2025
0bccc72
feat: spark source v2, reduce data transfer (#54)
jiaoew1991 Dec 10, 2025
994f4f7
feat: add nightly E2E testing infrastructure (#55)
jiaoew1991 Dec 11, 2025
bf4e408
fix: nightly e2e test (#56)
jiaoew1991 Dec 11, 2025
a9d2304
fix: Fix nightly (#57)
jiaoew1991 Dec 11, 2025
34797a4
fix: add AWS_DEFAULT_REGION for Pulumi S3 backend login (#58)
jiaoew1991 Dec 13, 2025
7740284
ci: Fix nightly (#59)
jiaoew1991 Dec 13, 2025
b302a9a
ci: Fix nightly (#60)
jiaoew1991 Dec 13, 2025
2b1ba4b
feat: dynamic partition (#64)
jiaoew1991 Dec 15, 2025
fbf5d53
test: remove unstable test (#67)
jiaoew1991 Dec 15, 2025
283969d
refactor: cleanup unused code (#68)
jiaoew1991 Dec 16, 2025
602b4a4
docs: update docs sync with code (#69)
jiaoew1991 Dec 16, 2025
3d9b63c
docs: add license (#71)
jiaoew1991 Dec 17, 2025
5337c6d
fix: build raydp package in solstice (#2)
jiaoew1991 Dec 23, 2025
8614d9f
feat: auto configure executor resources for raydp (#3)
jiaoew1991 Dec 24, 2025
05d2ae9
feat: integrate Tansu broker and client into solstice queue system (#5)
jiaoew1991 Jan 4, 2026
7770106
fix: wrong partition assign (#6)
jiaoew1991 Jan 5, 2026
5972e12
ci: opt for integration test (#7)
jiaoew1991 Jan 5, 2026
463d62a
feat: init version of debug dashboard (#8)
jiaoew1991 Jan 6, 2026
7ace779
feat: webui enhancemane (#9)
jiaoew1991 Jan 7, 2026
8b39996
docs: update agents documentation with design and todo sections (#10)
jiaoew1991 Jan 7, 2026
34c19ec
refactor: change metrics from pull to push (#11)
jiaoew1991 Jan 7, 2026
f7ad07a
fix: bugs of webui (#13)
jiaoew1991 Jan 7, 2026
b32ae46
feat: lineage webui (#14)
jiaoew1991 Jan 8, 2026
95e86c7
test: improve stablity of integration test (#15)
jiaoew1991 Jan 9, 2026
f73dad3
test: add chaos test (#16)
jiaoew1991 Jan 10, 2026
dea776c
test: fix ci (#17)
jiaoew1991 Jan 11, 2026
b8b72f1
feat: change aiokafka to confluent-kafka (#18)
jiaoew1991 Jan 12, 2026
0483813
feat: dedup + minhash operator (#19)
jiaoew1991 Jan 13, 2026
9a93c6d
feat: minhash dedupe support multi iterator dedupe (#20)
jiaoew1991 Jan 14, 2026
d30ea2b
ci: split integration and distributed to speed up (#21)
jiaoew1991 Jan 14, 2026
ec23c1e
feat: add llm inference (#22)
jiaoew1991 Jan 16, 2026
93bd17e
doc: update status of design doc (#23)
jiaoew1991 Jan 19, 2026
bbbca76
chore: use embedded inference replace pure worker (#24)
jiaoew1991 Jan 20, 2026
60684f1
feat: support exactly once (#25)
jiaoew1991 Jan 21, 2026
85356c4
docs: design doc for exactly once (#26)
jiaoew1991 Jan 22, 2026
758f4c7
chore: optimize for multi workers (#27)
jiaoew1991 Jan 25, 2026
a27dda7
chore: add new fault injection tests (#28)
jiaoew1991 Jan 25, 2026
2aa1419
fix: make CI more stable (#29)
jiaoew1991 Jan 26, 2026
98fd2e4
refactor: simplify API (#30)
jiaoew1991 Jan 26, 2026
36d8393
refactor: change data model of webui (#31)
jiaoew1991 Jan 27, 2026
67b68b9
refactor: move raydp & tansu-py to seperate dir (#32)
jiaoew1991 Jan 28, 2026
047d9c4
ci: optimize artifact (#33)
jiaoew1991 Jan 28, 2026
f7de8ef
fix: partition assign error in multi workers (#34)
jiaoew1991 Jan 31, 2026
893f448
feat: use new queue implement replace tansu (#35)
jiaoew1991 Feb 1, 2026
b9efccb
chore: optimize claim API (#36)
jiaoew1991 Feb 2, 2026
c36be4a
refactor: remove outdated code (#37)
jiaoew1991 Feb 4, 2026
bf78e5f
feat: redesign backpressure & webui (#38)
jiaoew1991 Feb 4, 2026
c4eff88
feat: support serve vllm (#39)
jiaoew1991 Feb 6, 2026
79f8838
chore: fix some ugly design (#40)
jiaoew1991 Feb 6, 2026
3e14340
refactor: remove checkpoint management code and update agent guidelin…
jiaoew1991 Feb 7, 2026
863c66f
chore: open mypy check (#42)
jiaoew1991 Feb 8, 2026
db71d8e
feat: use serve union find for minhash dedup (#43)
jiaoew1991 Feb 9, 2026
eedce94
refactor: rename subfolder names (#44)
jiaoew1991 Feb 9, 2026
049b234
feat: support s3/fs as payloadstore (#45)
jiaoew1991 Feb 9, 2026
b42b111
chore: detached mode for serve (#46)
jiaoew1991 Feb 10, 2026
b51fce9
chore: enhance pool scale up/down logic (#48)
jiaoew1991 Feb 11, 2026
ec804d1
chore: optimize pool logic (#49)
jiaoew1991 Feb 13, 2026
d5902c9
feat: support smart gpu scheduling (#50)
jiaoew1991 Feb 13, 2026
b105838
test: add integration tests for inference (#51)
jiaoew1991 Feb 14, 2026
c247d0f
chore: refactor webui API (#52)
jiaoew1991 Feb 18, 2026
3a10aed
refactor: new webui (#53)
jiaoew1991 Feb 18, 2026
4d114ac
chore: upgrade pyiceberg to 0.11.0 (#54)
jiaoew1991 Feb 18, 2026
9b60bb2
perf: further speed up serve integration tests (#55)
jiaoew1991 Feb 19, 2026
46882ad
doc: Claude memory construction (#56)
jiaoew1991 Feb 19, 2026
1f8d568
feat: add Union and Anti-Join source operators with vectorised filter…
jiaoew1991 Feb 23, 2026
c05d9de
refactor: simplify _process_and_ack and fix WebUI event count for mer…
jiaoew1991 Feb 23, 2026
5be5c56
refactor: shuffle machnism & docs (#59)
jiaoew1991 Mar 3, 2026
622a423
test: add deterministic simulation testing and clippy/fmt CI for work…
jiaoew1991 Mar 6, 2026
efa55af
feat: unify inter-stage data path with QueueGroup abstraction (#61)
jiaoew1991 Mar 9, 2026
ea848be
refactor: clean up code smells from QueueGroup unification (#62)
jiaoew1991 Mar 9, 2026
1966f5b
ci: add coverage collection and reporting for engine and workqueue-rs…
jiaoew1991 Mar 10, 2026
e6471c7
feat: add NVMe-tiered PayloadStore with Arrow Flight data plane (#65)
jiaoew1991 Mar 23, 2026
634dff5
test: container-based distributed tests for NVMe PayloadStore (#66)
jiaoew1991 Mar 24, 2026
5802ae6
docs: audit and fix design docs, reorganize TODO tracking (#68)
jiaoew1991 Mar 24, 2026
538953f
refactor: remove deprecated code and update INDEX.md (#69)
jiaoew1991 Mar 25, 2026
cc45131
fix: detect dead InferenceWorkers and write FAILED status (#70)
jiaoew1991 Mar 26, 2026
d8c75bf
feat: resource-aware scaling + rename AutoscaleConfig (#71)
jiaoew1991 Mar 26, 2026
1be5298
docs: add Dynamo inspirations and fix stale TODO items (#72)
jiaoew1991 Mar 27, 2026
a378656
fix: eliminate Arrow roundtrip in LanceSink + Lance WAL TODO (#73)
jiaoew1991 Mar 27, 2026
b10d50e
fix: production hardening — 7 bug fixes, WorkQueue atomic counters, A…
jiaoew1991 Mar 31, 2026
7375668
refactor: rename WorkQueue to Anvil and add Rust gRPC client (#75)
jiaoew1991 Mar 31, 2026
37c5396
docs: add bounded queue flow control design, deprecate multi-resource…
jiaoew1991 Mar 31, 2026
69c1952
docs: update flow control design with memory-budget-based bound sizing
jiaoew1991 Mar 31, 2026
1f67ba8
docs: add ADR-001 for bounded queue flow control decision
jiaoew1991 Mar 31, 2026
c16bccf
feat: bounded queue flow control (Phase 1) (#76)
jiaoew1991 Apr 1, 2026
65d0b73
refactor: modularize engine deps + upgrade all versions (#77)
jiaoew1991 Apr 1, 2026
6bcb628
fix: lazy import guards for optional deps + serve/webui group swap (#78)
jiaoew1991 Apr 2, 2026
8e4d3d2
fix: stabilize CI tests with proper claim timeouts and diagnostics (#79)
jiaoew1991 Apr 2, 2026
40e1441
fix: add diagnostics to remaining chaos stress tests (#80)
jiaoew1991 Apr 3, 2026
0dee30e
refactor: unified PipelineController (scaling + flow control + livene…
jiaoew1991 Apr 5, 2026
66884e3
chore: bump version to 0.2.2
jiaoew1991 Apr 6, 2026
a08d4fb
chore: rename packages to nurion-engine and nurion-control
jiaoew1991 Apr 7, 2026
50a0e8c
feat(raydp): cross-build for Spark 3.5 (Scala 2.12) and Spark 4.1 (Sc…
jiaoew1991 Apr 24, 2026
eae5dbf
fix(anvil): surface publish-commit race as warning; document root cau…
jiaoew1991 Apr 25, 2026
93e0a4b
fix(anvil): consistent-snapshot reads in check_queue_completion (#86)
jiaoew1991 Apr 25, 2026
a6a7ae8
refactor(anvil): single-mutex QueueState replaces seven atomics (#88)
jiaoew1991 Apr 26, 2026
2cbb96f
docs(lessons): retrospective on Anvil seven-atomics → one-mutex evolu…
jiaoew1991 Apr 26, 2026
103599f
ci: publish engine base image to GHCR (#91)
jiaoew1991 Jun 9, 2026
4c3dbd2
feat(serve): bring SGLang backend to parity with vLLM (#90)
jiaoew1991 Jun 9, 2026
1c30e2a
fix: install the raydp Python package (not just the jars) (#92)
jiaoew1991 Jun 10, 2026
d37852c
fix(raydp): keep shaded spark-connect-client jar off the Ray classpat…
jiaoew1991 Jun 10, 2026
7ff0109
feat(engine): build lance-spark bundle from main (lance-core 8.x) + p…
jiaoew1991 Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
54 changes: 54 additions & 0 deletions .agents/skills/fix-ci/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: fix-ci
description: Fix CI-discovered code quality (ruff) and mypy type check failures for the engine and/or control modules.
---

# Fix CI Code Quality and Type Checks

## Exact CI commands

```bash
# Lint + format (control)
cd control && uv run ruff check . && uv run ruff format --check .

# Lint + format (engine)
cd engine && uv run ruff check . && uv run ruff format --check .

# mypy (control)
cd control && uv run mypy control/

# mypy (engine)
cd engine && uv run mypy _internal/ nurion/
```

## Workflow

1. **Determine scope** — which modules have changes (engine, control, or both)
2. **Auto-fix ruff** — `ruff check --fix` then `ruff format`
3. **Run mypy** — read all errors, then fix them in source files
4. **Re-run all checks** — confirm fully clean before finishing

### Commands to fix and verify

```bash
# Fix ruff (engine)
cd engine && uv run ruff check . --fix && uv run ruff format .

# Fix ruff (control)
cd control && uv run ruff check . --fix && uv run ruff format .

# Check mypy (engine)
cd engine && uv run mypy _internal/ nurion/

# Check mypy (control)
cd control && uv run mypy control/
```

## Key rules

- Engine source lives in `engine/_internal/` — never `engine/engine/`
- mypy is gradual (`disallow_untyped_defs = false`); tests are excluded from mypy
- Prefer fixing the actual type error over adding `# type: ignore`
- Only use `# type: ignore[code]` as last resort (e.g. untyped third-party stubs)
- ruff: line-length = 100, target-version = py313
- After all fixes, every check must exit 0 with no output
202 changes: 202 additions & 0 deletions .agents/skills/webapp-testing/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
96 changes: 96 additions & 0 deletions .agents/skills/webapp-testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
name: webapp-testing
description: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
license: Complete terms in LICENSE.txt
---

# Web Application Testing

To test local web applications, write native Python Playwright scripts.

**Helper Scripts Available**:
- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)

**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.

## Decision Tree: Choosing Your Approach

```
User task → Is it static HTML?
├─ Yes → Read HTML file directly to identify selectors
│ ├─ Success → Write Playwright script using selectors
│ └─ Fails/Incomplete → Treat as dynamic (below)
└─ No (dynamic webapp) → Is the server already running?
├─ No → Run: python scripts/with_server.py --help
│ Then use the helper + write simplified Playwright script
└─ Yes → Reconnaissance-then-action:
1. Navigate and wait for networkidle
2. Take screenshot or inspect DOM
3. Identify selectors from rendered state
4. Execute actions with discovered selectors
```

## Example: Using with_server.py

To start a server, run `--help` first, then use the helper:

**Single server:**
```bash
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py
```

**Multiple servers (e.g., backend + frontend):**
```bash
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python your_automation.py
```

To create an automation script, include only Playwright logic (servers are managed automatically):
```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode
page = browser.new_page()
page.goto('http://localhost:5173') # Server already running and ready
page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute
# ... your automation logic
browser.close()
```

## Reconnaissance-Then-Action Pattern

1. **Inspect rendered DOM**:
```python
page.screenshot(path='/tmp/inspect.png', full_page=True)
content = page.content()
page.locator('button').all()
```

2. **Identify selectors** from inspection results

3. **Execute actions** using discovered selectors

## Common Pitfall

❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps
✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection

## Best Practices

- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly.
- Use `sync_playwright()` for synchronous scripts
- Always close the browser when done
- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs
- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`

## Reference Files

- **examples/** - Examples showing common patterns:
- `element_discovery.py` - Discovering buttons, links, and inputs on a page
- `static_html_automation.py` - Using file:// URLs for local HTML
- `console_logging.py` - Capturing console logs during automation
35 changes: 35 additions & 0 deletions .agents/skills/webapp-testing/examples/console_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from playwright.sync_api import sync_playwright

# Example: Capturing console logs during browser automation

url = 'http://localhost:5173' # Replace with your URL

console_logs = []

with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': 1920, 'height': 1080})

# Set up console log capture
def handle_console_message(msg):
console_logs.append(f"[{msg.type}] {msg.text}")
print(f"Console: [{msg.type}] {msg.text}")

page.on("console", handle_console_message)

# Navigate to page
page.goto(url)
page.wait_for_load_state('networkidle')

# Interact with the page (triggers console logs)
page.click('text=Dashboard')
page.wait_for_timeout(1000)

browser.close()

# Save console logs to file
with open('/mnt/user-data/outputs/console.log', 'w') as f:
f.write('\n'.join(console_logs))

print(f"\nCaptured {len(console_logs)} console messages")
print(f"Logs saved to: /mnt/user-data/outputs/console.log")
Loading
Loading