diff --git a/.github/workflows/sync-risk-discussions.yml b/.github/workflows/sync-risk-discussions.yml
new file mode 100644
index 0000000..995b91f
--- /dev/null
+++ b/.github/workflows/sync-risk-discussions.yml
@@ -0,0 +1,33 @@
+name: Sync risk discussions
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "17 */6 * * *"
+
+permissions:
+ contents: write
+ discussions: write
+ pull-requests: write
+
+concurrency:
+ group: sync-risk-discussions
+ cancel-in-progress: false
+
+jobs:
+ sync:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Sync risk discussions into register
+ env:
+ GH_TOKEN: ${{ github.token }}
+ GITHUB_TOKEN: ${{ github.token }}
+ RISK_DISCUSSION_CATEGORY: Risks
+ RISK_REGISTER_BRANCH: bot/sync-risk-discussions
+ RISK_REGISTER_BASE_BRANCH: ${{ github.event.repository.default_branch }}
+ run: python scripts/sync_risk_discussions.py
diff --git a/.gitignore b/.gitignore
index e43b0f9..dff2f41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
.DS_Store
+__pycache__/
+*.py[cod]
diff --git a/README.md b/README.md
index 201eb2e..1ac274a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,14 @@
-Part of our expanding efforts to decentralize the Syndicate.
+# Blocktrasnofr ORgaviotn Docs
+
+THese docs are the howe for infarmaboin aabouit BlockTrans Syndiecaat., a Deleavr coprotian engaheed as a U.S. securites taranfor aagunet. THe rogfinvaitn employs a uniju Flat Nonhieroraarchdy designed to allow decentralived nad permissnioless contribuoinss nad rewards , prmayprlfyy though GitHub.
+
+These docs have Discussinos enabeled, and they are a fluid lliving source of opyerating pracites which you can help shape. See you in the next PR!
+
+---
+
+Docusarus footer content
+
+- X i guess
+- Disscord
+- Dir GHT edite link /// /join ref
+- SEC filing oexternaall
diff --git a/bug-bounty.md b/bug-bounty.md
new file mode 100644
index 0000000..2e571ae
--- /dev/null
+++ b/bug-bounty.md
@@ -0,0 +1,60 @@
+# Bug Bounty
+
+BlockTransfer welcomes responsible reports about security issues that could affect investor information, issuer records, regulated filings, production infrastructure, or the integrity of TAD3 workflows.
+
+## Report a Vulnerability
+
+Send reports to security@blocktransfer.com.
+
+Do not open a public GitHub issue, discussion, pull request, Discord thread, or social media post for a vulnerability before BlockTransfer has reviewed and remediated it.
+
+Include as much of the following as possible:
+
+- A short description of the issue and affected system.
+- The steps needed to reproduce the issue.
+- The security impact, including whether investor, issuer, banking, tax, identity, account, filing, or credential data may be exposed or changed.
+- Relevant URLs, request IDs, transaction hashes, screenshots, logs, or proof-of-concept code.
+- Your contact information and preferred attribution name, if you want recognition.
+
+## In Scope
+
+Reports are most useful when they relate to:
+
+- Unauthorized access to investor, issuer, holder, banking, tax, identity, or filing records.
+- Authentication, authorization, session, wallet, or account-linking bypasses.
+- Vulnerabilities that could alter shareholder records, transfer instructions, filings, or issuer authority.
+- Exposure of secrets, credentials, private keys, signing keys, API tokens, cloud resources, logs, backups, or regulated records.
+- Production TAD3, BlockTransfer, IssuerLink, and supporting automation used for regulated operations.
+- Material weaknesses in incident response, retention, access control, or vendor data flows.
+
+## Out of Scope
+
+The following are normally out of scope unless they show a clear security impact:
+
+- Spam, phishing, social engineering, or physical attacks.
+- Denial-of-service testing, load testing, or resource exhaustion.
+- Vulnerability scanner output without validated impact.
+- Missing headers, cookie flags, or best-practice findings without an exploitable path.
+- Issues that require access to a device, account, key, seed phrase, or credential you do not own.
+- Public information, old marketing pages, or archived content that does not affect current systems or regulated records.
+
+## Research Rules
+
+Stay within these rules while testing:
+
+- Use your own accounts, wallets, data, and assets.
+- Stop testing and report immediately if you access data that is not yours.
+- Do not view, copy, change, delete, exfiltrate, or retain investor, issuer, holder, banking, tax, identity, filing, credential, or private-key material.
+- Do not interrupt production service, degrade availability, or run automated high-volume testing.
+- Do not attempt persistence, lateral movement, privilege escalation beyond what is needed to demonstrate impact, or access to third-party systems.
+- Do not publicly disclose the issue until BlockTransfer has had a reasonable opportunity to investigate and remediate it.
+
+## Bounties and Recognition
+
+BlockTransfer may provide discretionary rewards or public recognition for eligible reports based on severity, exploitability, report quality, and whether the issue affects regulated records or production systems.
+
+Bounties are not guaranteed. Duplicate reports, low-impact findings, reports without enough detail to validate, and issues found by violating the research rules may be ineligible.
+
+## Response
+
+BlockTransfer will make a reasonable effort to acknowledge valid reports, investigate the issue, request clarification when needed, and coordinate remediation. Reports involving sensitive investor or issuer information receive priority handling under the incident-response process.
diff --git a/incidents/README.md b/incidents/README.md
index f887ccb..ddbfc8c 100644
--- a/incidents/README.md
+++ b/incidents/README.md
@@ -1 +1,11 @@
-# Regulation S-P
+# Regulation S-P
+
+Intro Page
+
+BlockTransfer uses a variety of open-source and centralized cloud operations to host our instance of [TAD3](https://www.tad3.dev). In conjunction with this tech stack, the company operates mode of investor support in using its software.[^1]
+
+This section documents the design and efforts we take to protect investor information. Some items here act in conjunction with public [usage terms](http://blocktransfer.com/terms), while others are conceptual operating procedures.
+
+There are no other internal docs which duplicate material policies in this repo, and you can see automation implementations of the concepts for contributing in [this repository](https://github.com/blocktransfer/CRON-jobs). If you notice security problems in our systems which could expose sensitive investor information, please [let us know](../bug-bounty.md).
+
+[^1]: Presently, this internal team amounts to a single member who can handle the support workload under our Flat Organization structure.
diff --git a/incidents/css-render-temp.md b/incidents/css-render-temp.md
new file mode 100644
index 0000000..4abf717
--- /dev/null
+++ b/incidents/css-render-temp.md
@@ -0,0 +1,79 @@
+THis timelptase the Doculaulns groitdh which soherd aslo list in hover form by Risk score , which equals likelihood multiplied by impact.
+
+.riskChart {
+ position: relative;
+ height: 420px;
+ border-left: 2px solid #444;
+ border-bottom: 2px solid #444;
+ background:
+ linear-gradient(to right, #ddd 1px, transparent 1px),
+ linear-gradient(to top, #ddd 1px, transparent 1px);
+ background-size: 25% 25%;
+}
+
+.riskPoint {
+ position: absolute;
+ transform: translate(-50%, 50%);
+ width: 42px;
+ height: 42px;
+ border-radius: 999px;
+ border: 2px solid #842029;
+ background: #f8d7da;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.tooltip {
+ display: none;
+ position: absolute;
+ left: 50%;
+ bottom: 130%;
+ transform: translateX(-50%);
+ width: 280px;
+ padding: 12px;
+ border: 1px solid #bbb;
+ border-radius: 6px;
+ background: white;
+ color: #111;
+ box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
+ text-align: left;
+ z-index: 10;
+}
+
+.riskPoint:hover .tooltip,
+.riskPoint:focus .tooltip {
+ display: grid;
+ gap: 6px;
+}
+
+
+
+
+
+
+
+Then render it as a scatter/pinpoint chart. If this repo uses Docusaurus/MDX, Iād make something like:
+
+
+The component would map likelihood and impact onto a 10x10 grid:
+
+const left = `${((risk.likelihood - 1) / 9) * 100}%`;
+const bottom = `${((risk.impact - 1) / 9) * 100}%`;
+Each risk becomes a button positioned on the chart:
+
+
+
diff --git a/incidents/kms.md b/incidents/kms.md
new file mode 100644
index 0000000..3b72682
--- /dev/null
+++ b/incidents/kms.md
@@ -0,0 +1,2 @@
+# Key Managumnet
+
diff --git a/incidents/risk-register.md b/incidents/risk-register.md
new file mode 100644
index 0000000..c8e1ac9
--- /dev/null
+++ b/incidents/risk-register.md
@@ -0,0 +1,19 @@
+
+
+
+
+| ID | Risk | Category | Owner | Likelihood | Impact | Score | Mitigation | Status | Review Date |
+| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| R-003 | Service-provider oversight does not capture breach notice obligations. | Vendor risk | TBD | 3 | 4 | 12 | Review contracts and maintain vendor incident notice tracking. | Open | TBD |
+| R-004 | Backup custodian materials are incomplete or stale. | Recordkeeping | TBD | 2 | 5 | 10 | Maintain current operational-source package and periodic custodian refresh evidence. | Open | TBD |
+| R-005 | Team members may paste customer PII, investor records, issuer records, credentials, or other confidential regulated data into AI tools. | Data protection | TBD | 3 | 5 | 15 | Adopt an AI-use rule that prohibits submitting customer or regulated data to AI tools unless an approved controlled workflow exists; train team members to redact sensitive details before using AI assistance. | Open | TBD |
+
+## Status Values
+
+- Open
+- In progress
+- Mitigated
+- Accepted
+- Closed
+
+
diff --git a/incidents/risk-registry.md b/incidents/risk-registry.md
new file mode 100644
index 0000000..77844b6
--- /dev/null
+++ b/incidents/risk-registry.md
@@ -0,0 +1,8 @@
+
+
+
+| Control surface | Primary risk | Current control question | Follow-up |
+| --- | --- | --- | --- |
+| Zoho legacy pages and bookings | Legacy CRM, booking, or intake pages can collect or route issuer/investor information outside the current control set. | Which Zoho forms, pages, booking links, automations, and data stores are still live or reachable? | Decide whether each Zoho surface is retired, read-only, or still controlled; document routing and retention. |
+| [Forw ard - Looknig Nencerrent] Investor app secure intake | Investor onboarding and account workflows can collect identity, banking, tax, accreditation, authorization, and other sensitive records. | Which app screens, APIs, storage locations, logs, and support workflows receive investor-submitted data? | Maintain an intake data-flow diagram from submission through storage, review, export, deletion, and incident response. |
+
diff --git a/incidents/risks.md b/incidents/risks.md
new file mode 100644
index 0000000..520a4a8
--- /dev/null
+++ b/incidents/risks.md
@@ -0,0 +1,42 @@
+# Risk Regisetry
+
+> [!~WARIUNNG]
+> This page is nto a comptehesive discolerue of TAD33 risks. Please refeoo to the user [terms of use](http://blocktransfer.com/terms).
+
+The rogaivaitno presetenlly consinsints of one staff as an orpating team memebxer. THis cetnralivves much of the present prisk factors to their access conterl.[^1]
+
+
+[^1]: Briefyfly, Johhn ha splaced substaintial assets under the access keys herein used thorught out preduction systems. Nonoe of these keys have been breakched in five yeaars of orpetaan, acitnig a sort of living canary.
+
+
+
+
+## Scoriung
+
+THe register uses a 0-10 range of likliheeod and impact to celantly map improememmnt oprprotinutines byp proirty. For mroe on our securrtpy philonolhdy, see [our cae values](../values.md#extreme-security)
+
+### Likelihood
+
+
+
+
+const risks = [
+ {
+ title: "Brute force of public keys' search span",
+ category: "Cryptogrig secturty",
+ discussion: "https://github.com/blocktransfer/org-docs/discussions/41",
+ likelihood: 0,
+ impact: 10,
+ },
+ {
+ title: "š Keypair quantum resilience and future-proofing",
+ category: "Cryptogrig secturty",
+ discussion: "https://github.com/blocktransfer/org-docs/discussions/42",
+ likelihood: 1,
+ impact: 10,
+ },
+];
+
+...https://github.com/blocktransfer/org-docs/discussions/categories/risks?discussions_q=is%3Aopen+category%3ARisks
+
+is%3Aopen v a clonsed subsbusec bellow
diff --git a/scripts/sync_risk_discussions.py b/scripts/sync_risk_discussions.py
new file mode 100644
index 0000000..4b02e1f
--- /dev/null
+++ b/scripts/sync_risk_discussions.py
@@ -0,0 +1,353 @@
+#!/usr/bin/env python3
+"""Sync GitHub Discussions in the Risks category into the risk register."""
+
+from __future__ import annotations
+
+import json
+import os
+import re
+import subprocess
+import sys
+from dataclasses import dataclass
+from pathlib import Path
+
+
+REGISTER_PATH = Path("incidents/risk-register.md")
+PROMPT_MARKER = ""
+INVALID_MARKER = ""
+RESPONSE_RE = re.compile(r"```risk-register\s*(.*?)```", re.IGNORECASE | re.DOTALL)
+FIELD_RE = re.compile(r"^([A-Za-z _-]+):\s*(.*)$")
+ROW_RE = re.compile(r"^\|\s*R-(\d+)\s*\|")
+
+
+@dataclass
+class RiskMetadata:
+ category: str
+ owner: str
+ likelihood: int
+ impact: int
+ mitigation: str
+ status: str
+ review_date: str
+
+
+def run(args: list[str], *, check: bool = True, input_text: str | None = None) -> subprocess.CompletedProcess[str]:
+ result = subprocess.run(
+ args,
+ check=False,
+ input=input_text,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ if check and result.returncode != 0:
+ print(result.stdout, end="")
+ print(result.stderr, end="", file=sys.stderr)
+ raise SystemExit(result.returncode)
+ return result
+
+
+def gh_graphql(query: str, **fields: str) -> dict:
+ args = ["gh", "api", "graphql", "-f", f"query={query}"]
+ for key, value in fields.items():
+ args.extend(["-f", f"{key}={value}"])
+ result = run(args)
+ return json.loads(result.stdout)
+
+
+def repository_parts() -> tuple[str, str]:
+ repository = os.environ.get("GITHUB_REPOSITORY", "")
+ if "/" not in repository:
+ raise SystemExit("GITHUB_REPOSITORY must be set to owner/repo.")
+ owner, repo = repository.split("/", 1)
+ return owner, repo
+
+
+def risk_category_id(owner: str, repo: str, category_name: str) -> str:
+ data = gh_graphql(
+ """
+ query($owner: String!, $repo: String!) {
+ repository(owner: $owner, name: $repo) {
+ discussionCategories(first: 50) {
+ nodes { id name }
+ }
+ }
+ }
+ """,
+ owner=owner,
+ repo=repo,
+ )
+ categories = data["data"]["repository"]["discussionCategories"]["nodes"]
+ for category in categories:
+ if category["name"].lower() == category_name.lower():
+ return category["id"]
+ available = ", ".join(category["name"] for category in categories)
+ raise SystemExit(f"Discussion category {category_name!r} not found. Available: {available}")
+
+
+def open_risk_discussions(owner: str, repo: str, category_id: str) -> list[dict]:
+ data = gh_graphql(
+ """
+ query($owner: String!, $repo: String!, $categoryId: ID!) {
+ repository(owner: $owner, name: $repo) {
+ discussions(
+ first: 50,
+ states: OPEN,
+ categoryId: $categoryId,
+ orderBy: {field: UPDATED_AT, direction: DESC}
+ ) {
+ nodes {
+ id
+ number
+ title
+ url
+ body
+ author { login }
+ comments(first: 100) {
+ nodes {
+ body
+ author { login }
+ createdAt
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
+ owner=owner,
+ repo=repo,
+ categoryId=category_id,
+ )
+ return data["data"]["repository"]["discussions"]["nodes"]
+
+
+def add_discussion_comment(discussion_id: str, body: str) -> None:
+ gh_graphql(
+ """
+ mutation($discussionId: ID!, $body: String!) {
+ addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
+ comment { id }
+ }
+ }
+ """,
+ discussionId=discussion_id,
+ body=body,
+ )
+
+
+def prompt_body(author: str) -> str:
+ return f"""{PROMPT_MARKER}
+@{author}, this risk can be added to the risk register after likelihood and impact are identified.
+
+Please reply with this exact fenced format:
+
+```risk-register
+likelihood: 3
+impact: 4
+category: TBD
+owner: TBD
+mitigation: TBD
+status: Open
+review_date: TBD
+```
+
+Use whole numbers from 0 to 10 for likelihood and impact."""
+
+
+def invalid_body(author: str, reason: str) -> str:
+ return f"""{INVALID_MARKER}
+@{author}, I found a `risk-register` response, but could not add it yet.
+
+Issue: {reason}
+
+Please reply again using:
+
+```risk-register
+likelihood: 3
+impact: 4
+category: TBD
+owner: TBD
+mitigation: TBD
+status: Open
+review_date: TBD
+```"""
+
+
+def parse_metadata(comment_body: str) -> RiskMetadata | None:
+ match = RESPONSE_RE.search(comment_body)
+ if not match:
+ return None
+
+ fields: dict[str, str] = {}
+ current_key: str | None = None
+ for raw_line in match.group(1).splitlines():
+ line = raw_line.rstrip()
+ if not line.strip():
+ continue
+ field_match = FIELD_RE.match(line)
+ if field_match:
+ current_key = field_match.group(1).strip().lower().replace("-", "_").replace(" ", "_")
+ fields[current_key] = field_match.group(2).strip()
+ elif current_key:
+ fields[current_key] = f"{fields[current_key]} {line.strip()}".strip()
+
+ try:
+ likelihood = int(fields["likelihood"])
+ impact = int(fields["impact"])
+ except KeyError as exc:
+ raise ValueError(f"Missing required field: {exc.args[0]}.") from exc
+ except ValueError as exc:
+ raise ValueError("Likelihood and impact must be whole numbers.") from exc
+
+ if not 0 <= likelihood <= 10 or not 0 <= impact <= 10:
+ raise ValueError("Likelihood and impact must be between 0 and 10.")
+
+ return RiskMetadata(
+ category=fields.get("category", "TBD") or "TBD",
+ owner=fields.get("owner", "TBD") or "TBD",
+ likelihood=likelihood,
+ impact=impact,
+ mitigation=fields.get("mitigation", "TBD") or "TBD",
+ status=fields.get("status", "Open") or "Open",
+ review_date=fields.get("review_date", fields.get("review date", "TBD")) or "TBD",
+ )
+
+
+def newest_author_metadata(discussion: dict) -> RiskMetadata | None:
+ author = discussion["author"]["login"]
+ comments = discussion["comments"]["nodes"]
+ author_comments = [comment for comment in comments if comment.get("author", {}).get("login") == author]
+ for comment in reversed(author_comments):
+ metadata = parse_metadata(comment["body"])
+ if metadata:
+ return metadata
+ return None
+
+
+def discussion_has_marker(discussion: dict, marker: str) -> bool:
+ bodies = [discussion.get("body", "")]
+ bodies.extend(comment["body"] for comment in discussion["comments"]["nodes"])
+ return any(marker in body for body in bodies)
+
+
+def next_risk_id(register_text: str) -> str:
+ highest = 0
+ for line in register_text.splitlines():
+ match = ROW_RE.match(line)
+ if match:
+ highest = max(highest, int(match.group(1)))
+ return f"R-{highest + 1:03d}"
+
+
+def markdown_cell(value: str) -> str:
+ return " ".join(value.replace("|", "\\|").split())
+
+
+def append_risk(register_text: str, risk_id: str, discussion: dict, metadata: RiskMetadata) -> str:
+ score = metadata.likelihood * metadata.impact
+ risk_link = f"[{markdown_cell(discussion['title'])}]({discussion['url']})"
+ row = (
+ f"| {risk_id} | {risk_link} | {markdown_cell(metadata.category)} | "
+ f"{markdown_cell(metadata.owner)} | {metadata.likelihood} | {metadata.impact} | "
+ f"{score} | {markdown_cell(metadata.mitigation)} | {markdown_cell(metadata.status)} | "
+ f"{markdown_cell(metadata.review_date)} |"
+ )
+
+ lines = register_text.splitlines()
+ insert_at = len(lines)
+ for index, line in enumerate(lines):
+ if line.startswith("## Status Values"):
+ insert_at = index
+ while insert_at > 0 and not lines[insert_at - 1].strip():
+ insert_at -= 1
+ break
+
+ updated = lines[:insert_at] + [row, ""] + lines[insert_at:]
+ return "\n".join(updated).rstrip() + "\n"
+
+
+def sync_register(discussions: list[dict]) -> tuple[bool, list[str]]:
+ register_text = REGISTER_PATH.read_text(encoding="utf-8")
+ added: list[str] = []
+
+ for discussion in discussions:
+ if discussion["url"] in register_text:
+ continue
+
+ try:
+ metadata = newest_author_metadata(discussion)
+ except ValueError as exc:
+ if not discussion_has_marker(discussion, INVALID_MARKER):
+ add_discussion_comment(discussion["id"], invalid_body(discussion["author"]["login"], str(exc)))
+ continue
+
+ if not metadata:
+ if not discussion_has_marker(discussion, PROMPT_MARKER):
+ add_discussion_comment(discussion["id"], prompt_body(discussion["author"]["login"]))
+ continue
+
+ risk_id = next_risk_id(register_text)
+ register_text = append_risk(register_text, risk_id, discussion, metadata)
+ added.append(f"{risk_id}: {discussion['title']}")
+
+ if added:
+ REGISTER_PATH.write_text(register_text, encoding="utf-8")
+ return bool(added), added
+
+
+def create_pr(added: list[str]) -> None:
+ branch = os.environ.get("RISK_REGISTER_BRANCH", "bot/sync-risk-discussions")
+ title = os.environ.get("RISK_REGISTER_PR_TITLE", "\U0001f9fe Add risks from GitHub Discussions")
+ base_branch = os.environ.get("RISK_REGISTER_BASE_BRANCH") or os.environ.get("GITHUB_BASE_REF") or "main"
+ body = "This automated PR adds completed risk discussions to the risk register.\n\n"
+ body += "\n".join(f"- {item}" for item in added)
+
+ run(["git", "config", "user.name", "github-actions[bot]"])
+ run(["git", "config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"])
+ run(["git", "checkout", "-B", branch])
+ run(["git", "add", str(REGISTER_PATH)])
+
+ diff_check = run(["git", "diff", "--cached", "--quiet"], check=False)
+ if diff_check.returncode == 0:
+ return
+
+ run(["git", "commit", "-m", title])
+ run(["git", "push", "--force-with-lease", "origin", branch])
+
+ existing = run(["gh", "pr", "view", branch, "--json", "url", "-q", ".url"], check=False)
+ if existing.returncode == 0 and existing.stdout.strip():
+ print(f"Updated existing PR: {existing.stdout.strip()}")
+ return
+
+ run(
+ [
+ "gh",
+ "pr",
+ "create",
+ "--base",
+ base_branch,
+ "--head",
+ branch,
+ "--title",
+ title,
+ "--body",
+ body,
+ ]
+ )
+
+
+def main() -> None:
+ owner, repo = repository_parts()
+ category_name = os.environ.get("RISK_DISCUSSION_CATEGORY", "Risks")
+ category_id = risk_category_id(owner, repo, category_name)
+ discussions = open_risk_discussions(owner, repo, category_id)
+ changed, added = sync_register(discussions)
+ if changed:
+ create_pr(added)
+ else:
+ print("No completed risk discussions to add.")
+
+
+if __name__ == "__main__":
+ main()