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.

Controls
23
Version
1.0.0
Review by
2027-03-23
License
CC BY 4.0

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)?

Type II, 23 controls: 8 ready, 8 partial, 7 gaps. 10 dropped a grade from the design view.

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.

  1. CC1.1

    Written standards, enforced

    Type I: ReadyType II: Ready

    The 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 issuesrc/lib/newsletter/send-issue.js
    • The same check on outgoing records requestssrc/lib/foia/send.mjs
    • The list itselfchecked in code, not shown
  2. CC1.3, CC1.4

    Roles, background checks and training

    Type I: GapType II: Gap

    The 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.

  3. CC2.1, CC2.2

    A current description of the system

    Type I: ReadyType II: Partial

    The 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 modeldocs/capabilities/08-security-privacy-resilience.md
    • Its last-verified datedocs/capabilities/08-security-privacy-resilience.md
    • The system map's datasrc/app/architecture/architecture.mjs
  4. CC2.3

    Telling users what is happening

    Type I: ReadyType II: Partial

    The 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 modelsrc/lib/agents/status.js
    • The health-check schedule, paused.github/workflows/agent-schedules-tick.yml
    • The privacy pagesrc/app/privacy/page.jsx
  5. CC3.1, CC3.2

    A risk assessment that repeats

    Type I: PartialType II: Gap

    The 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 awaydocs/capabilities/08-security-privacy-resilience.md
    • The accepted residual riskdocs/capabilities/06-automation-and-ops.md
  6. CC4.1, CC4.2

    Checking that the controls still work

    Type I: ReadyType II: Partial

    The 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 silentsrc/lib/burn/model.mjs
    • The catalog kept in step with the real jobssrc/lib/burn/__tests__/catalog-drift.test.js
    • The freeze, written downdocs/ops/CRON-FREEZE.md
  7. CC5.2, CC5.3

    Policies deployed as tests

    Type I: ReadyType II: Ready

    The 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 gatesrc/lib/secrets/__tests__/inventory.audit.test.js
    • The rate-limit coverage gatescripts/audit/rate-limit-coverage.mjs
  8. CC6.1, CC6.3

    Least-privilege access

    Type I: ReadyType II: Ready

    The 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 laddersrc/lib/access-levels.js
    • Membership as the access listsrc/lib/tenancy/gate.mjs
    • Agents blocked from raising their own accesssrc/lib/iam/act-as.js
  9. CC6.2, CC6.3

    Granting, removing and reviewing access

    Type I: PartialType II: Gap

    The 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, auditedsrc/lib/iam/act-as.js
    • The grant recordssrc/lib/iam/grants.js
  10. CC6.1

    Credentials encrypted and accounted for

    Type I: ReadyType II: Partial

    The 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 encryptionsrc/lib/secrets/crypto.mjs
    • The change logsrc/lib/secrets/audit.js
    • The credential ledgersrc/lib/secrets/inventory.mjs
  11. CC6.6

    Protecting the edges

    Type I: ReadyType II: Ready

    The 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, classifiedscripts/audit/rate-limit-coverage.mjs
    • A webhook signature checksrc/lib/deploys/signature.mjs
    • The constant-time comparisonsrc/lib/bearer.js
  12. CC6.7

    Encryption in transit

    Type I: ReadyType II: Ready

    The 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 headernext.config.mjs
    • Why there is no full CSP yetnext.config.mjs
  13. CC7.1, CC6.8

    Finding vulnerabilities

    Type I: GapType II: Gap

    The 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
  14. CC7.2

    Noticing when something breaks

    Type I: ReadyType II: Partial

    The 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 funnelsrc/lib/observability.js
    • Stall detectionsrc/lib/deploys/classify.mjs
    • The watcher's live schedule.github/workflows/deploy-watch.yml
  15. CC7.3, CC7.4, CC7.5

    Responding to incidents

    Type I: PartialType II: Partial

    The 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 machinesrc/lib/agents/incidents-machine.mjs
    • The missing postmortem conventiondocs/capabilities/08-security-privacy-resilience.md
  16. CC8.1

    Changes are authorized, tested and approved

    Type I: PartialType II: Partial

    The 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
  17. CC9.2

    Vendor risk

    Type I: PartialType II: Gap

    The 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 keysrc/lib/secrets/inventory.mjs
  18. A1.2, A1.3

    Backups that restore

    Type I: ReadyType II: Gap

    The 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 encryptionscripts/ops/lib/archive-crypto.mjs
    • The recovery targetsdocs/ops/BACKUP-DR.md
  19. A1.1

    Capacity and cost limits

    Type I: ReadyType II: Ready

    The 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 brakesrc/lib/ai-spend/brake.mjs
    • The usage logsrc/lib/ai-spend/events.mjs
  20. C1.1

    Confidential records walled off

    Type I: ReadyType II: Ready

    The 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 testsrc/app/__tests__/pii-boundary.test.js
  21. C1.2

    Disposal on a schedule

    Type I: PartialType II: Gap

    The 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 policysrc/lib/retention/policy.mjs
    • The inbox gap, stateddocs/capabilities/08-security-privacy-resilience.md
    • The weekly sweep, paused.github/workflows/retention-sweep.yml
  22. PI1.2, PI1.3

    Accurate processing

    Type I: ReadyType II: Ready

    The 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 centssrc/lib/money/transactions.js
    • Figures recomputed on every changesrc/lib/research/__tests__/claims.test.js
    • Signed payment events onlysrc/lib/billing/stripe.mjs
  23. P1.1, P2.1

    Notice and choice

    Type I: PartialType II: Partial

    The 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 offsrc/app/privacy/page.jsx

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.

04 What it would take

  1. 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.

  2. Add a dependency scanner

    A scanner on every pull request closes the only control with nothing behind it at all.

  3. 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.

  4. Write the people paperwork

    A one-page role, a background check, an annual training record. Small, dull, and tested all the same.

  5. 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.

  6. 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.

Need something like this built?

I design and ship AI tools, full-stack apps, and data pipelines — end to end, to production. Tell me the problem in a sentence; I'll give you an honest read on fit within a day.

Work with me →