Skip to content

Start user-docs/ with the architecture page, and design the site around it - #104

Merged
kiwifellows merged 6 commits into
developfrom
docs/user-docs-first-slice
Aug 3, 2026
Merged

Start user-docs/ with the architecture page, and design the site around it#104
kiwifellows merged 6 commits into
developfrom
docs/user-docs-first-slice

Conversation

@kiwifellows

@kiwifellows kiwifellows commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What and why

D-10 chose user-docs/, plain Markdown, and a renderer decided later. This starts the directory and tests that choice against the hardest page in the plan rather than the easiest — an explainer with three complex SVG diagrams, written for security reviewers evaluating TOPS for their AWS organisation.

The choice holds. CommonMark plus tables carried the whole page. The full requirement list turns out to be: Markdown with tables, static assets served alongside, and a theme whose image CSS is one rule away from correct. Every MkDocs- or Docsify-class renderer meets that. Nothing found here argues for a framework, so the deferral stands.

User story

Not a feature. Documentation plus design, against the roadmap's User documentation site workstream and D-10.

What is in here

Four pages written, the priority-1 set from the content map:

Page For
start-here/how-tops-connects-to-aws.md Security reviewers approving TOPS for an AWS org
aws-accounts/what-the-iam-role-can-do.md The same reviewers, once they ask what the permissions grant
using-tops/reading-a-finding.md Whoever just ran their first scan
using-tops/resolving-a-finding.md The same person, once they have fixed something

Plus

Path
SECURITY.md Vulnerability policy. There was none, and README said "open an issue"
user-docs/assets/diagrams/*.svg Three standalone, self-theming diagrams at a 900px viewBox
user-docs/README.md Conventions: diagram rules, the seven voice rules, a link check
design/docs-site/information-architecture.md 34 pages across 8 sections, mapped against what exists
design/docs-site/archetypes/*.md Copyable skeletons with guidance inline
design/docs-site/wireframes.html Shell, three page archetypes, content map
design/architecture/ The exploration that produced the first page, marked non-canonical
deleted docs/quick-start.md 253 lines describing a Nuxt/Serverless/Prisma stack that is not the product

Findings worth reading before writing the next page

Two bugs that only exist once a diagram is standalone. Both fail as a broken image, which reads as a missing file rather than a syntax error:

  • HTML named entities are undefined in XML. A standalone .svg is parsed as XML, so — makes the file fail to render entirely. All numeric references now.
  • Angle brackets anywhere in the SVG's CSS, including inside comments, parse as tags.

The diagrams were re-authored at a 900px viewBox. Carried over at 1160px from the full-bleed HTML page, they scaled to 7.5px body text in a docs column — unreadable. At 900px with larger type and zones stacked vertically, they hold above 10px down to an 820px viewport:

viewBox Layout Body text Readable
1160px Standard column 7.5px No
1160px Wide variant @1680px 11.9px Only above ~1600px
900px Standard @1440px 12.4px Yes
900px Standard @820px 10.6px Yes

This withdraws a recommendation the design itself first made. An earlier draft proposed a wide-layout variant for explainer pages; it was compensating for over-wide diagrams. With them sized correctly the standard layout is enough and the site keeps one layout instead of two.

Theme requirement, in full: main p:has(> img) { max-width: none } (Markdown wraps images in a <p>, so the prose measure silently caps every diagram at 686px), plus the usual responsive breakpoints. That is all.

How it was tested

No application code changed, so no test suite ran. The page and diagrams were verified by measurement, not by eye:

  • All three SVGs parse as XML (xml.etree.ElementTree) — this is what caught both entity bugs.
  • Rendered through a deliberately minimal harness (python-markdown + ~60 lines of CSS, no framework) and measured at 1680 / 1440 / 1100 / 820px viewports.
  • Geometry checked by comparing every getBBox() against its containing rectangle: found a 4px card overlap and a text run escaping its card, both invisible in review, both fixed. Final state is clean — no overflow, no collisions, nothing outside the viewBox.
  • Both colour schemes resolve; no horizontal page scroll at any tested width.

Quality gate

  • Acceptance criteria are met — the first slice's page-one item, plus the design that sequences the rest
  • Solves the user problem simply — Markdown and three SVGs; the framework decision stays deferred
  • Follows the practices in docs/practices/ — no page written for a feature that does not exist, verified against PROGRESS.md
  • Tests written and passing — none. Documentation and design only
  • Documentation updated — this PR is documentation
  • No obvious performance issues — three static SVGs, ~8 KB each
  • Ready for production — the site is not deployed. Cloudflare Pages is not connected yet

Practices check

  • Security — no secrets. The page describes only what is already public in the templates
  • Simplicity — the wide-layout variant was removed once it proved unnecessary

Multi-tenancy, Database and Scan definitions are untouched.

Out of scope

  • Cloudflare Pages / DNS. docs.teemops.com does not resolve yet.
  • Trimming README.md's setup section to link into user-docs/. Worth doing once there is an install page to link to; doing it now would point at nothing.
  • teemops.com marketing site — different worktree, per the brief.
  • The other 30 pages. Mapped and prioritised, not written.

Two decisions for the reviewer

  1. A proposed amendment to D-10, suggested as D-13. D-10 scoped user-docs/ to start from "you're logged in", with README.md canonical for install. That holds for operators but not for reviewers, who read before anything is installed and will not open a GitHub README to do it. The proposal: user-docs/ owns evaluate and use; README.md stays canonical for the commands and the site links out. Not recorded in the log yet — that is your call.
  2. This page makes no claim that the SNS topic is locked down, deliberately, because #101 is open. It will want one sentence either way once that lands.

Findings from writing the pages

Both came from reading the code rather than restating the specs, and both changed what the docs say.

The child IAM role's write permissions are not used by anything. TOPS instantiates only STS, SNS and SQS clients — there is no SecurityHub, GuardDuty, Macie, Inspector, Config or CloudTrail code in the repository, and all 36 operations declared across rules/tasks/*/tasks.json are list, get or describe. So the role asks customers for write access across eight services on behalf of features that do not exist. Both pages say so, and show how to strip them. Worth its own issue: trim the template to what is used.

Also: s3:ListAllMyBuckets in TopsS3Bucket can never authorise — it does not support resource-level permissions and the statement scopes it to arn:aws:s3:::tops-config-*. Inert, but a reviewer would find it.

Two gaps closed. SECURITY.md now exists, and the dead docs/quick-start.md is deleted with its four inbound links repointed at the README.

Two blockers on SECURITY.md

The policy names two channels and neither answers yet:

  1. GitHub private vulnerability reporting is disabled on this repo — the "Report a vulnerability" link 404s until it is enabled in Settings → Security.
  2. security@teemops.com does not exist and needs routing.

🤖 Generated with Claude Code

…nd it

D-10 chose plain Markdown with the renderer deferred. This tests that choice
against the hardest page in the plan rather than the easiest, and it holds:
CommonMark plus tables carried the whole thing, and the requirement list is
Markdown with tables, static assets, and a theme whose image CSS is one rule
away from correct. Nothing here argues for a framework.

Two bugs only appear once a diagram is a standalone .svg rather than inline
HTML, and both fail silently as a broken image:

  - HTML named entities are undefined in XML. A standalone .svg is parsed as
    XML, so &mdash; makes the file fail to render entirely. All numeric now.
  - Angle brackets in the SVG's CSS, even inside a comment, parse as tags.

The diagrams were re-authored at a 900px viewBox with larger type and zones
stacked vertically instead of side by side. Carried over at 1160px they
scaled to 7.5px body text in a docs column, which is unreadable; at 900px
they hold above 10px down to an 820px viewport. That withdraws the wide-layout
variant this design first proposed for explainer pages -- it was compensating
for over-wide diagrams, and the site keeps one layout instead of two.

Both defects found in the re-authored set were geometric and invisible in
review: a 4px card overlap and a text run escaping its card. Checking every
getBBox() against its containing rectangle found both, and that check is
written into user-docs/README.md as a convention.

The IA maps 34 pages across 8 sections against what already exists -- 12 are
a porting job, 5 are scattered, 17 need writing. It also proposes one
amendment to D-10, for the decisions log: user-docs owns evaluate as well as
use, because a reviewer approving TOPS for an AWS org reads before anything
is installed and will not read a README to do it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kiwifellows kiwifellows added the documentation Improvements or additions to documentation label Aug 1, 2026
kiwifellows and others added 5 commits August 2, 2026 11:17
The IA said three archetypes and left it there, which is not enough to keep
17 pages written by different people months apart from diverging. Each
archetype is now a copyable skeleton with the guidance inline as comments
that do not render, so the rule is next to the thing it governs rather than
in a document nobody rereads.

The seven voice rules are the ones that are checkable rather than tasteful.
Two earn their place from work already done here: "never claim more than the
code does" comes from the child IAM role not being read-only, which is the
kind of overstatement a reviewer catches and then stops trusting the rest of
the site over -- so every explainer carries a "What we do not claim" section.
"Symptom before cause" is because troubleshooting is reached by searching an
error message, not by browsing a subsystem.

The writing order is dependency order, not importance order. Reading a
finding precedes resolving one, because resolution is meaningless to someone
who cannot yet interpret severity. Deploying the site waits until four real
pages exist, since a live site with one page invites filler.

Also fixes three dead links the architecture page shipped with -- it pointed
at pages the IA plans but nobody has written. They now point at the
repository files that exist today, and a link check is written into the
conventions so the next page cannot repeat it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…es publicly

A public repo with three open security issues and a reviewer-facing
architecture page had nowhere to report a vulnerability. README's Support
section said "open an issue", which for a vulnerability is the one thing
you do not want someone to do, so that now carries a carve-out.

Reporting is GitHub private advisories first, security@teemops.com as a
fallback for people who will not use GitHub. Commitments are deliberately
modest -- acknowledge in 5 working days, assess in 10 -- because a missed
public promise costs more credibility than a slow one, and this is a small
team.

Two sections do more work than the boilerplate. "What we are most worried
about" ranks the failure classes, led by cross-organisation data access,
because telling researchers where to look is the point of having a policy.
"Already known" lists #100, #101 and #102 with honest impact, so nobody
spends a weekend rediscovering the open SNS topic and nobody reports it as
though it were news.

Scope draws the line self-hosted products have to draw: an operator with a
shell on their own host is not a vulnerability, and neither is running with
APP_DEBUG on a public address.

BLOCKED ON TWO THINGS before this is true rather than aspirational: GitHub
private vulnerability reporting is disabled on the repo and must be turned
on, and security@teemops.com does not exist yet. Until both land the policy
names channels that do not answer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The architecture page summarised the permissions honestly but at a level a
reviewer will not accept on its own. This is the page they get pointed to
next: 2 managed policies, 21 inline ones, which 3 are resource-scoped and
which 18 carry Resource "*".

Two things came out of reading the template properly rather than
summarising it again.

The write permissions are not used by anything. TOPS instantiates only STS,
SNS and SQS clients; there is no SecurityHub, GuardDuty, Macie, Inspector,
Config or CloudTrail code in the repository at all, and every one of the 36
operations declared across rules/tasks/*/tasks.json is list, get or
describe. So the role asks for write access across eight services on behalf
of features that do not exist. The page says exactly that, and shows how to
strip them.

And s3:ListAllMyBuckets in TopsS3Bucket can never authorise -- it does not
support resource-level permissions and the statement scopes it to
arn:aws:s3:::tops-config-*. Inert rather than dangerous, but a reviewer
would find it, so we say it first.

The architecture page said the write half "exists for the operational
features that manage AWS security services on your behalf", which implied
those features ship today. Corrected there too -- claiming more than the
code does is the one thing this audience does not forgive.

Explainer archetype amended: lead with whatever answers "what shape is
this" fastest. Usually a diagram; on a permissions page an at-a-glance
table beats one, because the shape is counts and categories.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two pages a design partner hits within minutes of a first scan, and
nothing described either of them. Written in that order deliberately:
resolution is meaningless to someone who cannot yet interpret severity and
evidence.

The lifecycle table is the part worth getting right, and it is taken from
FindingsEngine rather than from the feature spec. What TOPS actually does:
a passing rule auto-resolves with reason "fixed"; a finding someone marked
resolved that is still failing gets reopened with the reason cleared; an
ignored finding that is still failing stays ignored. That asymmetry is the
whole design of D-11 -- resolved is a claim about the world and evidence can
contradict it, ignored is a standing judgement about the rule and evidence
cannot. The pages say so in those terms.

The row that earns its place is the last one: a scan that did not examine a
service leaves those findings untouched. Silence is not treated as good
news, and a reader who assumes otherwise would draw exactly the wrong
conclusion from an empty list.

resource_gone is deliberately not documented. It is a defined resolution
reason but is deferred behind PERF-2, so only "fixed" and "manual" can occur
today and only those two appear.

Every number asserted was checked against the rulesets rather than carried
over from the roadmap: 74 rules, 4 critical / 24 high / 32 medium / 14 low,
11 services, all 74 carrying remediation text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
docs/quick-start.md described a Nuxt 3 + Serverless + Prisma + PrimeVue
monorepo and ended with "Ready to proceed? I'll start initializing the
project structure". None of that stack is the product: TOPS is Laravel and
Inertia on Docker Compose. It was linked from docs/README.md, from
docs/architecture.md as "setup instructions", and from app/DOCS.md as
"Essential Setup", so anyone following the documented path was being sent
253 lines in the wrong direction.

Deleted rather than ported. Per D-10 the README is canonical for install,
so all four inbound links now point there instead.

Incidental, found by the same link check: every relative link in
docs/features/features-spec.md was written as ../docs/X from inside
docs/features/, which resolves to docs/docs/X -- thirteen dead links in one
file. Fixed, along with a reference to a practices/frontend.md that has
never existed; that content is in practices/design.md.

docs/, app/DOCS.md and README.md now have no dead relative links at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kiwifellows
kiwifellows merged commit 92581f4 into develop Aug 3, 2026
3 checks passed
@kiwifellows
kiwifellows deleted the docs/user-docs-first-slice branch August 3, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant