Lab 5
Read-only Lab specification
Lab specification
Lab 5 — A Spacebar Developer's Guide
Prerequisites: Labs 1–4. The component diagrams and architecture understanding from prior labs are inputs — verify them and update as needed.
Prepares for: The rest of the semester. This is a permanent reference document to help you (and your agents!) with your project.
Estimated time: 2–3 hours total across the two weeks.
Please be sure to read the "Agent Interaction Log" section before you start working on Section 1!
Overview
The Developer's Guide is a very useful document: it is a plain-English description of how to work on and navigate through the project, as well as a description of the architecture, goals, coding practices, and design decisions of the project. Generally it also includes information about organization and navigation of the codebase as well. Envision that we are targeting a software engineer joining the project mid-semester who needs to understand what Spacebar is, how to get it running, and how to add a feature. Or (and this is actually going to be useful to you!) it can be AI agent reading the document as context. Both audiences need specificity; unlike an ADR, the document will be more accessible and slightly less formal.
For the assignment you will produce a permanent, verified reference document for the Spacebar codebase. Every claim must be verified against the actual code — inaccurate technical content is penalized in grading. The document will be written with agent assistance, but agent-generated content that has not been verified is a liability, not an asset. The appendix (agent interaction log) is where you document what the agent got wrong and how you corrected it. That log is graded: reviewers want to see evidence of genuine verification, not a statement that "everything looked right."
Section 1 — Architecture Overview (Required)
Produce a concise architecture overview by carrying forward the corrected diagram from Lab 4 and annotating it for a newcomer. Use Mermaid graph LR to create visualizations where they clarify the guide. The overview should cover:
- The major modules (
src/api/,src/gateway/,src/util/,src/cdn/,src/webrtc/,src/schemas/) - Their responsibilities (one phrase per node)
- The key communication paths between them (labeled with what crosses the boundary: TypeScript function calls, HTTP requests, WebSocket frames, event bus messages, database queries)
- Layer boundaries (HTTP edge / application logic / domain model / persistence)
Start from the Lab 4 architecture diagram. Add the documentation needed by a newcomer: responsibilities, key data flows, and any corrections discovered while writing the guide. For each change relative to Lab 4, write one annotation explaining what you changed and why.
You'll have created three diagrams in the labs:
- Lab 3 inventories components and communication;
- Lab 4 explains layers and contracts;
- Lab 5 consolidates the verified result into a usable reference.
Verification requirement: Cite the source for each key boundary and data flow. You do not need to cite every repeated edge in the inherited diagram; prioritize the interfaces a newcomer would use or modify.
A citation is worth writing when it tells the reader something they could not guess. Compare:
src/api/→src/util/: route handlers callgetPermission()(src/util/util/Permissions.ts:241), which loads the channel, guild, and member from the database and then delegates the actual bit arithmetic toPermissions.finalPermission()at line 315. Example call site:src/api/util/handlers/Message.ts:305.
against
"src/api/depends onsrc/util/for permissions,"
which an arrow on the diagram already indicated. The useful version names the function, distinguishes the wrapper that does I/O from the pure function that does resolution, and gives a call site the reader can open.
Check every citation you write. Both the path and the symbol must be real — a plausible-looking path that does not exist is a common failure.
Section 2 — Module Guide (Required)
For each major src/ directory, write a structured entry, along these lines:
### src/[module]/
**Owns:** [what this module is responsible for — one sentence]
**Public interface:** [key exports — 2–4 specific function/class names with one-line descriptions]
**Depends on:** [which other src/ modules this one imports from]
**Key invariants:** [what must always be true about this module's behavior]
**Common pitfalls:** [one or two things that are easy to get wrong when modifying this module]What counts as an invariant
An invariant is something that must be true of a module's behavior at all times — not a description of what the module does, but a rule that holds across every code path, and that something would break if violated. For instance, invariants should capture properties (or enforced code paths) that ensure data or system integrity.
The test is whether you could write code that violates it. If you cannot imagine the violation, you have written a description rather than an invariant.
| Not an invariant | An invariant |
|---|---|
"src/util/ handles permissions." | "Every permission decision goes through Permissions.finalPermission(); no route computes a bitfield inline." |
| "The gateway sends events to clients." | "A client never receives an event for a channel it lacks VIEW_CHANNEL on." |
| "Entities map to database tables." | "An entity's related collections are undefined unless the query names them in relations; code that reads them without asking gets silence, not an error." |
The left column cannot be violated, because it does not claim anything specific. The right column can — and each violation is a real bug someone could write this afternoon.
Ask Claude:
"What invariant does [module] maintain? What breaks if it's violated? Cite the specific function or comment in the code where this invariant is enforced."
Verify each invariant claim against the actual source. A hallucinated invariant is worse than no invariant — it gives false confidence to the next reader, human or agent.
Section 3 — Getting Started Guide (Required)
A step-by-step guide that a new engineer can follow on a clean machine to get from zero to a running server with a passing test suite. Every command must be verified to work.
Required content:
- Prerequisites (Node.js version, PostgreSQL, OS requirements)
- Clone and install:
git clone,npm install - Build:
npm run build— explain what this does (TypeScript compile + schema generation) - Database setup:
npm run sync:db— explain what this does and why it is safe for dev but not for production - Configuration:
export CONFIG_PATH=./config.json— show the minimal config.json - Start the server:
npm start— explain which services start together - Health check:
curl http://localhost:3001/healthz - Run the test suite:
npm test— explain what the smoke test actually checks
Add troubleshooting notes for the two most common setup failures you personally encountered. These should be specific ("if you see error X, the cause is Y and the fix is Z"), not generic.
Write for a clean machine. Assume the reader has the operating system and nothing else — no cloned repository, no installed dependencies, no running database, and none of the environment variables you set weeks ago and forgot. Every step will be evaluated against that assumption, and a step that only works because of something already on your laptop counts as a step that fails.
Section 4 — How to Add a Feature (Required)
Produce a step-by-step walkthrough using a concrete example. Choose one of:
- Adding a new message field (e.g.,
edited_attimestamp visible in the API response) - Adding a new channel type flag
- Adding a new permission bit
The walkthrough must cover every step in the chain:
- TypeORM entity — add the field to the entity class in
src/database/entities/. Show the decorator syntax (@Column, etc.). - Database sync —
npm run sync:dbapplies the change to the schema. - DTO / schema — update the request/response type.
A DTO (Data Transfer Object) is the shape of data as it crosses a boundary, as distinct from the shape it has in storage. The Message entity in src/database/entities/ is what a message is in the database, with every column and relation. The DTO is what a client receives — often a subset, sometimes with fields renamed or computed. Keeping them separate is what lets you add an internal column without leaking it into the public API.
In Spacebar, src/util/dtos/ holds the hand-written transfer shapes shared between the API and the gateway, and src/schemas/ holds JSON schemas generated from TypeScript types for request validation. Which one your feature touches depends on whether the field crosses the API boundary, the gateway boundary, or both — determine this by reading, and say which you chose and why.
- Route handler — update the relevant handler in
src/api/routes/to read/write the new field. - Gateway event — if the new field should appear in real-time events, update the event payload in
src/gateway/. - Test — write one integration test that sends a request and verifies the new field appears in the response.
- Schema regeneration —
npm run generate:schemaregeneratesassets/schemas.json.
Each step should have:
- A one-sentence goal for the step
- The relevant code change (≤15 lines)
- The command to verify the step worked (a test, a curl request, or a build command)
The walkthrough must be reproducible by a reader who has your Getting Started section working and nothing else — no knowledge of which file you meant, and no ability to ask you.
Section 5 — Known Technical Debt (Required)
Identify at least three items of technical debt using agent assistance.
Ask Claude Code:
"Analyze the Spacebar codebase for technical debt. Look for: TODO/FIXME comments, inconsistent patterns across similar files, missing error handling, overly complex functions, and places where the same logic is duplicated. List at least five candidates, citing specific file:line for each."
For each of the three items you select, write:
- Description: What the problem is, in plain English.
- Location: File path and line range.
- Impact: What breaks or becomes hard if this debt is not addressed.
- Remediation: What a clean version would look like (one sentence or a short code sketch).
- Risk vs. effort judgment: State the relative remediation effort, and the risk of leaving it unaddressed, for each item.
Summarize the three in a small table with a column for risk, a column for effort, and a column for what you would actually do about it. The point of the table is the last column: two items with identical risk and effort can still warrant different decisions depending on what else is happening in the codebase.
Note: The // TODO: do not deny any permissions if admin comment at src/util/util/Permissions.ts:126 is one candidate — it documents a known behavioral gap that is also the focus of Project 1's conformance testing. If you include it, verify the exact line number against the current source.
Agent Interaction Log (Required Appendix)
For each of the five sections, record:
- What prompt(s) you used
- What the agent got wrong (specific incorrect claims, wrong line numbers, invented function names, etc.)
- What corrections you made and how you verified them
This log is graded. "The agent was accurate throughout" is unlikely — even well-calibrated agents make verifiable errors on unfamiliar codebases. If you genuinely found no errors, explain specifically how you verified each claim.
Deliverables
Start from the [Lab 5 submission template](lab-05-submission.md) — it is the developer-manual.md skeleton with all five required sections and the appendix. (The template is also downloadable from the bottom of the Lab 5 assignment page on Agent P.)
developer-manual.md, at your repository root, onmaster, with CI green.- The Agent Interaction Log as the final appendix inside that same file. Do not split it into a second document — the appendix is graded alongside the sections it describes.
Submitting Your Lab
Unlike most labs, Lab 5's deliverable lives at your repo root, not in a lab5/ folder — it is a permanent document, not a throwaway lab artifact. A tag, not the current state of master, is what gets graded.
The Agent Interaction Log goes inside `developer-manual.md`, as its final appendix. One file, one submission.
git add developer-manual.md
git commit -m "Submit Lab 5"
git push origin master
git tag lab5-submission
git push origin lab5-submissionOff campus, connect to the Penn VPN first. To fix something before the deadline, commit the fix, push master, then move the tag:
git tag -d lab5-submission && git push origin :refs/tags/lab5-submission
git tag lab5-submission && git push origin lab5-submissionGrading
| Criterion | Points |
|---|---|
| All five sections present and complete | 2 |
| Technical accuracy (spot-checked against the code) | 1 |
| "How to add a feature" is complete and reproducible | 1 |
| Agent interaction log shows genuine verification | 1 |
Reproducibility: Both Section 3 and Section 4 are evaluated by following them exactly as written, from a clean machine, without filling in anything you left implicit. A missing export, an unstated prerequisite, or a command that silently depends on your shell history is a failure of the step.
Accuracy penalty: For each factual inaccuracy found in the document (wrong file path, wrong function name, wrong line number, incorrect description of behavior), 0.1 points will be deducted up to a maximum of 0.5 points. Verify your claims.
Agent P