Skip to content

Commit f030b9f

Browse files
Merge branch 'master' into berickson/20260417-log-rotation
2 parents 4800d29 + 43c7564 commit f030b9f

14 files changed

Lines changed: 400 additions & 271 deletions

File tree

‎Dockerfile‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ FROM python:3.10
22
RUN git config --global --add safe.directory /app
33
WORKDIR /app
44

5+
# Future work:
6+
# - This image currently uses an older Python base image version.
7+
# - Update the Python version to align with current LO/WO support targets.
8+
# - Some configurations may also require extra roster files mounted/provided
9+
# at runtime (for example: admins.yaml or teachers.yaml).
10+
# - Consider a layered setup:
11+
# 1) maintain a shared "base LO" Docker image
12+
# 2) extend it with a WO-specific image (or other module-set images)
13+
514
# TODO start redis in here
615
# see about docker loopback
716
RUN apt-get update && \

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ that the core approach and APIs are correct.
6565
We have a short guide to [installing the system](docs/tutorials/install.md).
6666
Getting the base system working is pretty easy. To create a new module
6767
for the system to use, check out our [cookiecutter module guide](docs/tutorials/cookiecutter-module.md).
68+
For a current package/module overview, see the [module inventory](docs/reference/module_inventory.md).
6869

6970
### System requirements
7071

‎autodocs/reference.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Detailed, structured information about APIs, configurations, and technical detai
99
- :doc:`Linting Rules <docs/reference/linting>` - Review the automated checks that keep the codebase healthy and how to run them locally.
1010
- :doc:`Testing Strategy <docs/reference/testing>` - Explore the testing layers we rely on and guidelines for writing reliable tests.
1111
- :doc:`Versioning and Releases <docs/reference/versioning>` - See how we tag releases, manage dependencies, and maintain backward compatibility.
12+
- :doc:`lo_assets Built Packages <docs/reference/lo_assets>` - Understand how prebuilt package artifacts are published and consumed.
13+
- :doc:`Module Inventory <docs/reference/module_inventory>` - Get a quick at-a-glance list of current monorepo modules and their roles.
1214
- :doc:`Module Reference <modules>` - Dive into the autogenerated API reference for Python modules within Learning Observer.
1315
- :doc:`API Reference <api>` - Inspect the internal functionality of the system.
1416

@@ -23,5 +25,7 @@ Detailed, structured information about APIs, configurations, and technical detai
2325
docs/reference/linting.md
2426
docs/reference/testing.md
2527
docs/reference/versioning.md
28+
docs/reference/lo_assets.md
29+
docs/reference/module_inventory.md
2630
modules
2731
api

‎devops/README.md‎

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,65 @@ We would like to be cross-platform, and evenually support both
1010
Debian-based distros and RPM-based distros. We're not there yet
1111
either. We'd also like to support multiple cloud providers. We're not
1212
there yet either. However, we probably won't accept PRs which move us
13-
away from this goal.
13+
away from this goal.
14+
15+
## Create an AWS account and an EC2 instance.
16+
* Select Ubuntu, nano AMI. The cost should be 0.5 cents per hour.
17+
* In security groups, add HTTP, HTTPS rules. Open up only to your computer's IP address (the client).
18+
* Launch instance.
19+
* Suppose your instance public DNS is {ec2_ip}, e.g., ec2-18-223-122-172.us-east-2.compute.amazonaws.com.
20+
* Create aSSH key pair, save PEM file say under ~/.ssh, chmod to u+r.
21+
22+
## Set up the EC2 instance.
23+
* SSH into the machine: `bash ssh -i {pem_file} ubuntu@{ec2_ip}`.
24+
* (Optional) Create a user account: sudo useradd {user}
25+
* Download the server code (same repository as the extension):
26+
```bash
27+
cd
28+
git clone https://github.com/ETS-Next-Gen/writing_analysis.git writing_analysis
29+
```
30+
* Install Ansible.
31+
```bash
32+
sudo apt-get update
33+
sudo apt-get upgrade
34+
sudo apt-get install ansible
35+
````
36+
* Configure Ansible.
37+
sudo pico /etc/ansible/hosts
38+
Add
39+
```
40+
[localhost]
41+
127.0.0.1
42+
```
43+
* `cd ~/writing_analysis/configuration`.
44+
* Run `sudo ansible-playbook local.yaml`. This may take a while on an EC2 nanon machine.
45+
If all goes well, you should see an output with no errors, like this:
46+
```
47+
bash
48+
...
49+
PLAY RECAP ******************************************************************************************
50+
127.0.0.1 : ok=5 changed=4 unreachable=0 failed=0
51+
```
52+
* Navigate to http://{ec2_ip}; you should see the message "Welcome to nginx!" if it's working.
53+
54+
## Obtain a free domain name
55+
* Go to noip.com.
56+
* Sign up
57+
58+
## Obtain a free SSL Certificate Using Certbot
59+
* Run the following commands:
60+
```bash
61+
sudo apt-get install software-properties-common
62+
Sudo add-apt-repository universe
63+
sudo add-apt-repository ppa:certbot/certbot
64+
sudo apt-get update
65+
sudo apt-get install certbot python-certbot-nginx
66+
```
67+
```
68+
bash
69+
sudo certbot --nginx
70+
```
71+
-- Put in your {mydomain}.hopto.org address.
72+
-- Choose 1 - no redirect.
73+
74+
## Stand up a backend server on the EC2 instance.

‎docs/concepts/system_settings.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ logic expands directories into sorted file lists, then loads each file as a
3434
ends in `.pmss`. Any other file suffix is skipped with a warning so you can
3535
keep README files or notes alongside the rulesets without breaking startup.
3636

37+
This argument is intended for normal startup entry points too (for example, a
38+
`Makefile` target or deployment startup scripts), not just ad-hoc local runs.
39+
For example:
40+
41+
```bash
42+
python -m learning_observer.main --pmss-rulesets creds.yaml schools.pmss
43+
```
44+
3745
## The role of `creds.yaml`
3846

3947
Most installations load configuration from `creds.yaml`. When the process

‎docs/how-to/offline_replay.md‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ Use the helper functions in `learning_observer/offline.py` to initialize the env
2121
```bash
2222
python - <<'PY'
2323
import asyncio
24+
import learning_observer.settings
2425
from learning_observer import offline
2526
26-
# Prepare the in-memory KVS and reducers for offline replay
27-
offline.init('creds.yaml')
28-
29-
# TODO: Offline replay currently initializes PMSS with default rulesets only.
30-
# If you need custom `.pmss` overlays or alternate YAML files, update the
31-
# offline initializer to accept ruleset paths.
32-
27+
# Provide YAML settings and optional PMSS overlays directly.
28+
offline.init(
29+
'creds.yaml',
30+
pmss_rulesets=['creds.yaml', 'schools.pmss']
31+
)
3332
3433
# Replace this path with the study log you want to replay
3534
log_path = "/path/to/your/session.study.log"
@@ -42,6 +41,15 @@ asyncio.run(main())
4241
PY
4342
```
4443

44+
`offline.init()` accepts `pmss_rulesets` and forwards them to
45+
`learning_observer.settings.init_pmss_settings(...)` before loading settings.
46+
This mirrors startup behavior where the web server accepts
47+
`--pmss-rulesets creds.yaml schools.pmss`.
48+
49+
The offline module still does not expose a first-class CLI parser like
50+
`learning_observer.main`; there is a TODO in `offline.py` to add an
51+
`argparse`-based entrypoint for settings and ruleset arguments.
52+
4553
- `process_file` only accepts study logs ending in `.study.log` or `.study.log.gz` and will reject other log types.
4654
- If you do not provide a `userid`, a random safe username is generated to avoid inadvertently reusing PII from the log.
4755

‎docs/reference/lo_assets.md‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# lo_assets Built Package Reference
2+
3+
This document explains how Learning Observer consumes built packages from [`ArgLab/lo_assets`](https://github.com/ArgLab/lo_assets), why this exists, and current operational caveats.
4+
5+
## Why `lo_assets` exists
6+
7+
Some frontend-related packages require an `npm` build step before they are usable. That build tooling is not always available on deployment servers, so we publish prebuilt artifacts to `lo_assets` and fetch them during setup/startup.
8+
9+
In `lo_assets`, each package typically has its own directory containing:
10+
11+
- versioned archives (for example, `package-name-v1.2.3.tar.gz`)
12+
- a `package-name-current.tar.gz` pointer file (a plain-text file containing the current archive filename)
13+
14+
## Where this repository is referenced in Learning Observer
15+
16+
### 1) Python package install path (`Makefile`)
17+
18+
The top-level `Makefile` installs `lo_dash_react_components` by:
19+
20+
1. downloading `lo_dash_react_components-current.tar.gz` from `lo_assets`
21+
2. reading the returned filename
22+
3. installing that resolved tarball with `pip`
23+
24+
This is implemented in the `install` target and is currently specialized to LODRC.
25+
26+
### 2) Runtime frontend asset fetch (`remote_assets.py`)
27+
28+
`learning_observer.remote_assets.fetch_module_assets()` supports a generic pointer-file workflow for prebuilt frontend bundles (for example exported Next.js apps):
29+
30+
1. read a `*-current.tar.gz` pointer file from `lo_assets`
31+
2. resolve it to a concrete archive name
32+
3. download and extract the archive into a target module directory
33+
34+
This logic is used for modules that ship prebuilt frontend assets outside of the main repo.
35+
36+
## Package-specific notes
37+
38+
### LODRC (`lo_dash_react_components`)
39+
40+
- This is a Python package, so downloading and reinstalling is an acceptable update path.
41+
- Current behavior is handled by the top-level `Makefile` install process.
42+
43+
### Portfolio Diff (`wo_portfolio_diff`)
44+
45+
- This is a Next.js-derived frontend bundle copied into `modules/wo_portfolio_diff/wo_portfolio_diff`.
46+
- Current fetch logic can pull the bundle when assets are missing.
47+
- Current behavior does **not** automatically refresh when a newer remote bundle exists and local assets are already present.
48+
49+
## Operational caveats
50+
51+
- Whenever a new package version is published in `lo_assets`, the `*-current.tar.gz` pointer file should also be updated to point to that new archive.
52+
- Most consuming code paths intentionally resolve the `current` pointer rather than pinning a hard-coded version.
53+
- In some cases, users may need to remove local assets and re-run setup/startup steps to force retrieval of the latest bundle.
54+
55+
## Future improvement (TODO)
56+
57+
A generic Learning Observer startup check should:
58+
59+
1. track the resolved remote archive version in a local state file
60+
2. compare local version vs. current `*-current.tar.gz` pointer target
61+
3. auto-refresh assets when the remote current version changes
62+
63+
This would eliminate manual remove-and-refetch workflows and make behavior consistent across modules.

‎docs/reference/module_inventory.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Module Inventory
2+
3+
This page is a quick-reference inventory of modules/packages in this monorepo:
4+
what they are and what they do.
5+
6+
## Current modules at a glance
7+
8+
### Common modules
9+
10+
| Module | What it does |
11+
| --- | --- |
12+
| `lo_dash_react_components` | Shared custom Dash UI components used across dashboards. |
13+
| `lo_gpt` | Shared interfaces/utilities for accessing LLMs. |
14+
| `lo_template_module` | Cookiecutter template used to scaffold new Learning Observer modules. |
15+
16+
### Additional module
17+
18+
| Module | What it does |
19+
| --- | --- |
20+
| `ccss` | Common Core State Standards-related package/resources. |
21+
22+
### Writing-focused modules
23+
24+
| Module | What it does |
25+
| --- | --- |
26+
| `portfolio_diff` | Next.js code for the portfolio dashboard UI. |
27+
| `wo_classroom_text_highlighter` | Classroom text highlight dashboard module. |
28+
| `wo_bulk_essay_analysis` | Classroom dashboard for bulk essay analysis (LLM-assisted workflows). |
29+
| `wo_portfolio_diff` | Learning Observer entrypoint module for the built/deployed `portfolio_diff` dashboard. |
30+
| `writing_observer` | Core writing-process analytics module and integrations. |
31+
32+
### Unused / superseded modules
33+
34+
| Module | Current state |
35+
| --- | --- |
36+
| `language_tool` | Standalone module is not actively used; relevant functionality now lives in `writing_observer`. |
37+
| `websocket_debug` | Standalone module is not actively used; websocket debugging is mostly handled by scripts in `scripts/`. |
38+
39+
### Prototype modules
40+
41+
| Module | What it does | Current status |
42+
| --- | --- | --- |
43+
| `lo_action_summary` | Dashboard listing student events/actions. | Prototype. |
44+
| `lo_lti_grade_demo` | Demo for LTI grade submission and reading flow. | Prototype/demo. |
45+
| `lo_event` | Event-focused module (includes Next.js dashboard component work). | Moved to its own repository. |
46+
| `toy-assess` | Initial LO Blocks implementation. | Being phased out (still used in some studies). |
47+
| `lo_toy_sba` | Save/load state module used primarily with `toy-assess` + `lo_event`. | Prototype support module. |
48+
49+
### Legacy prototype dashboards (not fully migrated)
50+
51+
When the communication protocol changed to an async-generator pattern, some
52+
prototype dashboards were not migrated.
53+
54+
| Module | What it does | Note |
55+
| --- | --- | --- |
56+
| `wo_common_student_errors` | Aggregate classroom LanguageTool dashboard. | Legacy prototype; may be folded into newer dashboard patterns. |
57+
| `wo_document_list` | Toy dashboard showing documents across students. | Legacy prototype. |
58+
| `wo_highlight_dashboard` | Initial highlight dashboard implementation. | Superseded by newer highlight work. |

‎learning_observer/learning_observer/offline.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,17 @@
4141
}
4242

4343

44-
def init(settings=INTERACTIVE_SETTINGS):
44+
def init(settings=INTERACTIVE_SETTINGS, pmss_rulesets=None):
4545
'''
4646
Initialize the Learning Observer library.
4747
48+
Args:
49+
settings (str|dict): Path to a YAML settings file or an in-memory
50+
settings dictionary.
51+
pmss_rulesets (list[str]|None): Optional PMSS ruleset files/directories
52+
to initialize before loading settings. If omitted, defaults to the
53+
standard PMSS initialization behavior.
54+
4855
Returns:
4956
None
5057
@@ -55,8 +62,10 @@ def init(settings=INTERACTIVE_SETTINGS):
5562
# anything before we've loaded the settings. This might not be necessary,
5663
# depending on the (still-changing) startup order
5764
learning_observer.log_event.DEBUG_LOG_LEVEL = learning_observer.log_event.LogLevel.NONE
58-
# TODO: Allow offline callers to pass PMSS ruleset files or directories.
59-
learning_observer.settings.init_pmss_settings()
65+
learning_observer.settings.init_pmss_settings(pmss_rulesets)
66+
# TODO: Add an argparse-powered CLI entrypoint (similar to main.py) so
67+
# offline workflows can accept settings and PMSS rulesets directly from
68+
# command-line arguments without wrapper scripts.
6069
learning_observer.settings.load_settings(settings)
6170
learning_observer.prestartup.startup_checks_and_init()
6271
learning_observer.kvs.kvs_startup_check() # Set up the KVS

0 commit comments

Comments
 (0)