Research · Self-assessment · as of 2026-09-23
SOC 2 Readiness for a One-Person Platform
What one operator can prove, what one operator cannot, and why a paused job is the difference between a Type I and a Type II.
A SOC 2 report comes in two types. A Type I asks whether each control was designed well. A Type II asks whether it actually ran, every week, for months. This platform passes the first question far more often than the second, and the difference has two causes in equal measure: jobs that were built, tested and then switched off to save money, and reviews that were done once and never put on a calendar.
This is a self-assessment, not an audit. Only an independent CPA firm can issue a SOC 2 report, and this platform has not engaged one. Nothing on this page claims compliance.
01 The board
Did the control actually operate, without gaps, across a period (usually three to twelve months)?
Security CC
- CC1.1Written standards, enforced
- CC1.3, CC1.4Roles, background checks and training
- CC2.1, CC2.2A current description of the system
- CC2.3Telling users what is happening
- CC3.1, CC3.2A risk assessment that repeats
- CC4.1, CC4.2Checking that the controls still work
- CC5.2, CC5.3Policies deployed as tests
- CC6.1, CC6.3Least-privilege access
- CC6.2, CC6.3Granting, removing and reviewing access
- CC6.1Credentials encrypted and accounted for
- CC6.6Protecting the edges
- CC6.7Encryption in transit
- CC7.1, CC6.8Finding vulnerabilities
- CC7.2Noticing when something breaks
- CC7.3, CC7.4, CC7.5Responding to incidents
- CC8.1Changes are authorized, tested and approved
- CC9.2Vendor risk
Confidentiality C
Processing integrity PI
Privacy P
The worksheet lists every in-scope control with both grades and the open gaps, with room to describe your own controls. It is built in your browser.
02 The controls
Each control names the files that implement it. The repository is private, so the paths are listed rather than linked; a test checks every one on each change.
- CC1.1
Written standards, enforced
Type I: ReadyType II: ReadyThe criterion asks
The organization writes down what it expects of the people who run the system and holds them to it.
What this platform does
A written list of lines the site never crosses is enforced in code: every outbound channel runs the same check before anything is sent, and a test keeps the written list and the code in step.
Still open
Nobody signs an acknowledgment of the standards.
The one-person problem
The only person bound by the standards is the person who wrote them, so an acknowledgment would be a signature on one's own memo.
- The newsletter refusing to send a flagged issue
src/lib/newsletter/send-issue.js - The same check on outgoing records requests
src/lib/foia/send.mjs - The list itselfchecked in code, not shown
- The newsletter refusing to send a flagged issue
- CC1.3, CC1.4
Roles, background checks and training
Type I: GapType II: GapThe criterion asks
Reporting lines and roles are defined, people with access are screened, and everyone takes security training when hired and every year after.
What this platform does
None of this exists in a form an auditor could test. There is one person: no org chart, no hiring process, no training record.
Still open
An org chart, a background check, and a dated training record, even for a company of one.
The one-person problem
An auditor will still test the one person against these criteria. The fix is paperwork, not engineering: a written role, a screening record and an annual training certificate.
- CC2.1, CC2.2
A current description of the system
Type I: ReadyType II: PartialThe criterion asks
The organization knows and documents what the system is, where its boundaries are, and who can reach what.
What this platform does
A written threat model names every kind of actor, what each can reach and what bounds it. A public system map shows the parts and how they connect.
Still open
The threat model was last verified on July 4, 2026, and nothing schedules the next review.
- The threat model
docs/capabilities/08-security-privacy-resilience.md - Its last-verified date
docs/capabilities/08-security-privacy-resilience.md - The system map's data
src/app/architecture/architecture.mjs
- The threat model
- CC2.3
Telling users what is happening
Type I: ReadyType II: PartialThe criterion asks
Users are told about the system's commitments and about incidents that affect them.
What this platform does
A public status page reports each component as up, degraded or down, from an hourly health check, and a privacy page lists what the site stores in a visitor's browser.
Still open
The hourly health check that feeds the status page is one of the scheduled jobs paused since July 29, 2026, so the page shows the last reading rather than a live one.
- The status page's model
src/lib/agents/status.js - The health-check schedule, paused
.github/workflows/agent-schedules-tick.yml - The privacy page
src/app/privacy/page.jsx
- The status page's model
- CC3.1, CC3.2
A risk assessment that repeats
Type I: PartialType II: GapThe criterion asks
Risks to the system are identified and analyzed, and the assessment is repeated as things change.
What this platform does
The threat model names its known gaps instead of hiding them, and the one path that merges code without a person has its remaining risk written down and accepted.
Still open
The assessment was written once. There is no second one to show that it repeats, and no calendar that makes it.
- A gap named instead of invented away
docs/capabilities/08-security-privacy-resilience.md - The accepted residual risk
docs/capabilities/06-automation-and-ops.md
- A gap named instead of invented away
- CC4.1, CC4.2
Checking that the controls still work
Type I: ReadyType II: PartialThe criterion asks
The organization evaluates whether its controls are present and functioning, and acts on what it finds.
What this platform does
Every scheduled job is listed in a catalog that a test keeps in step with the real schedules, and a dashboard sorts each job into fired, failing or silent.
Still open
The dashboard reports nearly every scheduled job as paused: all of them were switched off on July 29, 2026 to cut the monthly bill. The checks that run on every code change kept running.
- Fired, failing or silent
src/lib/burn/model.mjs - The catalog kept in step with the real jobs
src/lib/burn/__tests__/catalog-drift.test.js - The freeze, written down
docs/ops/CRON-FREEZE.md
- Fired, failing or silent
- CC5.2, CC5.3
Policies deployed as tests
Type I: ReadyType II: ReadyThe criterion asks
Control activities are put in place through technology and through written policies that people follow.
What this platform does
Policies here are tests that run on every change: the credential inventory, rate-limit coverage, the boundary around client records, the lines the site never crosses. The build fails if any one of them breaks.
- The test suite on every push and pull request
.github/workflows/ci.yml - The credential inventory gate
src/lib/secrets/__tests__/inventory.audit.test.js - The rate-limit coverage gate
scripts/audit/rate-limit-coverage.mjs
- The test suite on every push and pull request
- CC6.1, CC6.3
Least-privilege access
Type I: ReadyType II: ReadyThe criterion asks
Access to information and systems is limited to what each person or process needs.
What this platform does
Access is an ordered ladder: none, view, edit, admin. A member of a shared board sees only that board, and an unknown board and a board you are not on both answer "not found". Automated agents act only through tokens scoped to a grant.
- The access ladder
src/lib/access-levels.js - Membership as the access list
src/lib/tenancy/gate.mjs - Agents blocked from raising their own access
src/lib/iam/act-as.js
- The access ladder
- CC6.2, CC6.3
Granting, removing and reviewing access
Type I: PartialType II: GapThe criterion asks
Access is granted through a process, removed when it is no longer needed, and reviewed on a schedule.
What this platform does
Grants are recorded, and every use of an agent's access token is written to an audit log. But nobody reviews the full list of who can reach what on a schedule.
Still open
A dated, recurring access review with a record of what was removed.
The one-person problem
The reviewer and the person whose access is being reviewed would be the same person.
- Each agent token use, audited
src/lib/iam/act-as.js - The grant records
src/lib/iam/grants.js
- Each agent token use, audited
- CC6.1
Credentials encrypted and accounted for
Type I: ReadyType II: PartialThe criterion asks
Credentials that protect the system are themselves protected.
What this platform does
Stored credentials are encrypted with AES-256-GCM, changed from an admin screen without a redeploy, and every change is logged. A test fails when code uses a credential the ledger has never heard of.
Still open
Keys are rotated when someone decides to, not on a calendar.
- The encryption
src/lib/secrets/crypto.mjs - The change log
src/lib/secrets/audit.js - The credential ledger
src/lib/secrets/inventory.mjs
- The encryption
- CC6.6
Protecting the edges
Type I: ReadyType II: ReadyThe criterion asks
The system is protected against threats from outside its boundaries.
What this platform does
Every route that writes data must be rate-limited, gated behind sign-in, verified by a signature, or listed with a written reason. A test fails on any new route that is none of these. Inbound webhooks are checked with a constant-time comparison.
Still open
The rate limiter counts per server instance, not across all of them, and the security doc says so.
- Every write route, classified
scripts/audit/rate-limit-coverage.mjs - A webhook signature check
src/lib/deploys/signature.mjs - The constant-time comparison
src/lib/bearer.js
- Every write route, classified
- CC6.7
Encryption in transit
Type I: ReadyType II: ReadyThe criterion asks
Information moving between the system and its users is protected.
What this platform does
Every response tells browsers to use HTTPS only, for two years, subdomains included.
Still open
There is no full Content Security Policy. The config explains why one was not added blind.
- The HTTPS-only header
next.config.mjs - Why there is no full CSP yet
next.config.mjs
- The HTTPS-only header
- CC7.1, CC6.8
Finding vulnerabilities
Type I: GapType II: GapThe criterion asks
The organization detects new vulnerabilities and unauthorized or malicious software.
What this platform does
Nothing scans for them. No automated dependency updates or vulnerability scans are configured, and the install step in CI skips npm's own audit.
Still open
A dependency scanner on every pull request, and a record of what was found and fixed.
- The install step that skips the audit
.github/workflows/ci.yml
- The install step that skips the audit
- CC7.2
Noticing when something breaks
Type I: ReadyType II: PartialThe criterion asks
The system is monitored for anomalies that could mean an attack, an error or an outage.
What this platform does
Errors go through one reporting function. A watcher compares the live deployment with the latest commit and alerts when production stalls, and it runs off the hosting provider so it still fires during that provider's outage.
Still open
The deploy watcher still runs on its schedule. The hourly site health check does not.
- The one error funnel
src/lib/observability.js - Stall detection
src/lib/deploys/classify.mjs - The watcher's live schedule
.github/workflows/deploy-watch.yml
- The one error funnel
- CC7.3, CC7.4, CC7.5
Responding to incidents
Type I: PartialType II: PartialThe criterion asks
Incidents are evaluated, contained, fixed and learned from.
What this platform does
Failed checks open, acknowledge and resolve incidents through one state machine, and alerts page the operator by Telegram.
Still open
There is no written response plan and no postmortem convention. The security doc names the missing convention as a gap.
- The incident state machine
src/lib/agents/incidents-machine.mjs - The missing postmortem convention
docs/capabilities/08-security-privacy-resilience.md
- The incident state machine
- CC8.1
Changes are authorized, tested and approved
Type I: PartialType II: PartialThe criterion asks
Changes to the system are authorized, designed, tested, approved and documented before they reach production.
What this platform does
Every change lands through a pull request that must pass lint, the full test suite and a build that matches production. One narrow path merges small agent-written fixes without a person, and it fails closed.
Still open
Nobody but the author approves a change. The one automated reviewer was switched off when its API budget went to zero.
The one-person problem
Separation of duties needs a second person: whoever writes a change should not be the one who approves it.
- The required checks
.github/workflows/ci.yml - The production-parity build
.github/workflows/prod-parity.yml - The automated reviewer, paused
.github/workflows/pr-qa-review.yml - The one merge without a person
.github/workflows/pm-automerge.yml
- The required checks
- CC9.2
Vendor risk
Type I: PartialType II: GapThe criterion asks
Risks from vendors and business partners are assessed and managed.
What this platform does
The credential ledger names every outside service the site holds a key for, so the vendor list is complete and a test keeps it that way.
Still open
Nobody collects the vendors' own SOC 2 reports or writes down a review of them.
- Every vendor with a key
src/lib/secrets/inventory.mjs
- Every vendor with a key
- A1.2, A1.3
Backups that restore
Type I: ReadyType II: GapThe criterion asks
Data is backed up, and recovery is tested.
What this platform does
A weekly job dumps the business-critical tables, encrypts the archive, copies it offsite, then restores it into a scratch database and checks the rows, because a backup that cannot restore is not a backup. A runbook sets recovery targets for each zone.
Still open
The job has been paused since July 29, 2026 with every other scheduled job, and it only runs once a database connection string is added. For a Type II, a paused backup is a failed control.
- The backup and restore test
.github/workflows/backup-verify.yml - The archive encryption
scripts/ops/lib/archive-crypto.mjs - The recovery targets
docs/ops/BACKUP-DR.md
- The backup and restore test
- A1.1
Capacity and cost limits
Type I: ReadyType II: ReadyThe criterion asks
Capacity is managed so the system can meet its commitments.
What this platform does
AI spend is logged on every call, and a brake stops paid calls at the monthly ceiling before a runaway bill can take the service down. Public endpoints are rate-limited.
- The spend brake
src/lib/ai-spend/brake.mjs - The usage log
src/lib/ai-spend/events.mjs
- The spend brake
- C1.1
Confidential records walled off
Type I: ReadyType II: ReadyThe criterion asks
Confidential information is identified and protected.
What this platform does
A client's records can be imported only by that client's own module. A test scans the codebase and fails if anything else reaches in, and it also fails if it scanned too few files to mean anything.
- The boundary test
src/app/__tests__/pii-boundary.test.js
- The boundary test
- C1.2
Disposal on a schedule
Type I: PartialType II: GapThe criterion asks
Confidential information is disposed of when it is no longer needed.
What this platform does
A written retention policy deletes dinner-guest replies 30 days after the event and retires stale scraped listings, and unclaimed anonymous boards are deleted after 30 days.
Still open
The mail inbox declares a retention period it does not enforce, and both deletion sweeps are paused.
- The retention policy
src/lib/retention/policy.mjs - The inbox gap, stated
docs/capabilities/08-security-privacy-resilience.md - The weekly sweep, paused
.github/workflows/retention-sweep.yml
- The retention policy
- PI1.2, PI1.3
Accurate processing
Type I: ReadyType II: ReadyThe criterion asks
Inputs and processing are complete and accurate.
What this platform does
Money is stored as whole cents, never as floating-point dollars. Published figures are recomputed on every change. Payment webhooks are accepted only with a valid signature.
- Whole cents
src/lib/money/transactions.js - Figures recomputed on every change
src/lib/research/__tests__/claims.test.js - Signed payment events only
src/lib/billing/stripe.mjs
- Whole cents
- P1.1, P2.1
Notice and choice
Type I: PartialType II: PartialThe criterion asks
People are told what personal information is collected and are given choices about it.
What this platform does
A privacy page lists every cookie the site sets. The one optional analytics cookie stays off unless the visitor accepts it.
Still open
The notice covers the browser. It does not describe the personal information held in the private household and client tools.
- The opt-out that keeps analytics off
src/app/privacy/page.jsx
- The opt-out that keeps analytics off
03 What one person cannot do alone
Most of SOC 2 is engineering, and engineering scales down to one person. A few criteria are about people checking each other, and those do not.
Written standards, enforced
The only person bound by the standards is the person who wrote them, so an acknowledgment would be a signature on one's own memo.
CC1.3, CC1.4Roles, background checks and training
An auditor will still test the one person against these criteria. The fix is paperwork, not engineering: a written role, a screening record and an annual training certificate.
CC6.2, CC6.3Granting, removing and reviewing access
The reviewer and the person whose access is being reviewed would be the same person.
CC8.1Changes are authorized, tested and approved
Separation of duties needs a second person: whoever writes a change should not be the one who approves it.
04 What it would take
Turn the paused safety jobs back on
Backups and the retention sweeps first. They cost minutes a week, and without them a Type II fails on day one.
Add a dependency scanner
A scanner on every pull request closes the only control with nothing behind it at all.
Put the reviews on a calendar the build enforces
Access, risk and vendors each get a review-by date and a test that fails when it passes, the same way this page's own date works.
Write the people paperwork
A one-page role, a background check, an annual training record. Small, dull, and tested all the same.
Find a second approver
A retained reviewer who approves changes to protected paths. Separation of duties cannot be automated by the person it is meant to separate.
Then pick an auditor and a window
A Type I first, to test the design, then a Type II over at least three months of the controls actually running.
05 How this page stays honest
The evidence is tested
Every file named above must exist and still contain what it is cited for. If a control disappears, the build fails before this page can keep grading it.
The paused jobs are checked
A test reads the backup, retention and health-check schedules. If one starts running again, the build fails until its grade here is raised to match.
The grades expire
A test fails once 2027-03-23 passes. Someone has to regrade every control and publish a new version.
06 Versions
- 1.0.0 2026-09-23 First assessment: 23 controls across all five Trust Services Categories, graded for design and for operation.
Reuse it under CC BY 4.0. Cite it from its research record.