Skip to content

docs(aaas): A0 design — per-tenant single-writer RFC and threat model - #675

Merged
Danceiny merged 4 commits into
mainfrom
claude/gotry-issue-674-afe827
Oct 28, 2026
Merged

Danceiny merged 4 commits into
mainfrom
claude/gotry-issue-674-afe827

Conversation

@Danceiny

Copy link
Copy Markdown
Owner

Refs #674

The founder chartered AaaS on 2026-10-21. That met the D-15 trigger (the old tracker #275 stays as history) and fired the re-review conditions of ADR-14, ADR-15, ADR-17 and ADR-23. This PR is #674's A0 step: a reviewable design before any state-layer code. It is docs only; nothing changes at runtime.

What it proposes (docs/rfc/aaas-rfc.md, status proposal, with its zh-CN mirror)

  • State: keyed single writer per tenant. One SQLite ledger per tenant, at most one writer at any instant, and ownership held as a lease whose epoch fences the off-node copies. cr-sqlite is rejected because eventual consistency cannot guarantee consume-once. A shared Postgres or MySQL ledger is the named fallback, with switch triggers; as the primary binding it would rewrite the synchronous, kernel-pinned ledger and its callers.
  • Tenant model: a tenant is one end user, derived at the trusted seam from the authenticated BFF principal and never taken from payloads, tools or the model. An organization is the deploying party, which hotelbyte's own vocabulary calls a "tenant".
  • Durability: an explicit RPO instead of "no loss". Asynchronous off-node copies are admissible while writes stay sealed; RPO 0 is required before M5 can unseal on AaaS.
  • Topology: an intranet gotry tier behind the BFF, a new boundary ADR replacing C2, and still never browser-reachable (C16).
  • ADR re-review kickoff in RFC §5: ADR-14/15/17/23 hold with additions; ADR-16 stays frozen and its deferred items activate.
  • Threat model (docs/design/aaas-security-design.md): threats S-1 to S-16, each with today's state, a proposed control and the falsification test of the phase that proves it.
  • Reconciled authorities: architecture §8 status markers plus one note, and the §10 D-15 row (trigger met, shorter row); roadmap §1; master outline gate G6; docs index; decision queue.

Evidence on 8b126e6b3e7a7781c0d278217f13167a72a22ea1

  • node scripts/check-docs-i18n.mjs: exit 0 (DOCS I18N SYNC OK: 93 对双语文档结构对等).
  • node scripts/check-doc-readability.mjs and --self-test: exit 0.
  • cd ts && npx tsx scripts/g5-guard.ts: exit 0 (722 tracked files, no unauthorized G5 reference).
  • Relative-link check over the 14 changed files: 0 broken.
  • cd ts && npx tsc --noEmit: exit 2, 58 errors, all in ts/scripts/booking-copilot-gateway-chat-adapter-tests.ts. The same 58 errors occur on main at da99c5e and are tracked in test: make gateway-chat adapter proof pass strict TypeScript #672. This PR changes no TypeScript (git diff --stat origin/main -- ts/ is empty).
  • Full run-all-tests.sh: not run locally, because the change is docs only.
  • Minimal E2E: N/A for docs. The burden of proof is the gates and the link check above.

CI note. On main at da99c5e, the "typecheck + full regression (22/24)" jobs already stop at the Typecheck step with those 58 errors (#672). This PR's CI will stop there too; the dist-compatibility jobs remain a meaningful signal.

Review ask. Answer Q1–Q8 in RFC §8.1. Replying "as recommended" accepts all eight. A1 starts only after acceptance.

huangzhen.0505 added 2 commits October 26, 2026 17:00
The founder chartered AaaS on 2026-10-21, which met the D-15 trigger and
fired four ADR re-review conditions, so A0 needs a reviewable design before
any state-layer code is written.

- rfc/aaas-rfc (en + zh-CN), status proposal: keyed single writer per tenant
  (one SQLite ledger per tenant behind an epoch-fenced lease), tenant vs
  organization model, a declared RPO (async off-node copies while writes stay
  sealed; RPO 0 before M5 unseals on AaaS), an intranet tier topology,
  failure modes, ADR-14/15/16/17/23 kickoff findings, founder decisions
  Q1-Q8 and read-only facts F-1 to F-4.
- design/aaas-security-design (en + zh-CN): threat model S-1 to S-16, each
  with today's state, a proposed control and the falsification test of the
  phase that proves it.
- Reconciled authorities: architecture §8 rows marked triggered 2026-10-21
  plus one pointer note; §10 D-15 trigger met (row shortened, section now
  7107 of 7300 bytes); roadmap §1 AaaS row; master outline gate G6; docs
  index; decision queue.

Refs: #674
Constraint: Docs only; no runtime, schema, dependency or kernel-manifest change; writes stay sealed.
Rejected: cr-sqlite for service state | eventual consistency cannot guarantee consume-once.
Rejected: shared Postgres/MySQL as the primary binding | rewrites the synchronous kernel-pinned ledger; kept as the named fallback.
Confidence: medium (design proposal; facts F-1 to F-4 not yet verified)
Scope-risk: narrow
Tested: check-docs-i18n (93 pairs OK); check-doc-readability and --self-test OK; g5-guard OK; relative-link check over the 14 files, 0 broken.
Not-tested: full run-all locally (docs only). tsc --noEmit exits 2 identically on main (58 pre-existing errors in ts/scripts/booking-copilot-gateway-chat-adapter-tests.ts, tracked in #672); this commit changes no TypeScript.
… tsc

The proof broke the whole-project strict typecheck (58 errors), and CI
stops at that Typecheck step before smoke and the full regression, so
every PR on main, this one included, lost its regression signal.

- Declare the surface the proof drives on the undeclared JS adapter
  (dependencies, stream options, model info) and type emitted chunks with
  the harness's own StreamChunk union from @deepseek-ai/dsh-llm.
- Type the mock server (RequestListener, ServerResponse, AddressInfo
  narrowing) and the wire request bodies; make adapterFor's captured
  argument optional.
- Narrow chunks and the tool-call block through small helpers instead of
  unchecked property reads, and read error codes from unknown via one guard.
- Every assertion is unchanged.

Fixes #672
Constraint: Test file only; no suppression directive, no src, tsconfig or package change.
Rejected: A .d.ts beside dsh-llm-gateway-chat.js | widens the change into src and the shipped package.
Confidence: high
Scope-risk: narrow
Tested: Node v26.9.0: cd ts && npx tsc --noEmit exit 0 (was exit 2, 58 errors); adapter proof exit 0 before and after; smoke.ts exit 0; mutation check: a misspelled chunk field and an un-narrowed tool-call read both fail tsc.
Not-tested: full run-all locally; CI runs it on Node 22/24 once Typecheck passes.
The founder judged the file-permission discussion over-designed: access
control belongs at the presentation layer, and ops-level redundancy waits
for a real need (2026-10-26).

- RFC: forget deletes the tenant ledger and its off-node copies, with no
  per-tenant keys; the boundary ADR drops the network ACL; a non-goal
  records the rule; decision Q5 (crypto-shredding) is removed, so Q6-Q8
  become Q5-Q7.
- Security design: drops the operator actor, the operator-reads-files
  threat (umask, encrypted copies, audit), key rotation and principal
  audit, and the encryption and retention open questions; S-12 now deletes
  the copies; a rejected option records the rule; threats renumber to S-15.
- Decision queue: seven decisions instead of eight.

Refs: #674
Constraint: Docs only; bilingual pairs edited together.
Confidence: high
Scope-risk: narrow
Tested: check-docs-i18n (93 pairs OK); check-doc-readability OK; relative-link check over the 6 files, 0 broken; zh-CN punctuation scan clean.
Not-tested: nothing beyond the doc gates (no code changed).
Danceiny added a commit that referenced this pull request Oct 27, 2026
…676)

#669's fresh-port retries ask the task factory for a new port after retiring
the current one. A factory that returns one shared instance handed back the
closed port, so next() rejected untyped with booking_planner_run_port_closed.
main's full regression had failed on this since 6599423 (Node 22 and 24).

- Both retry branches refuse a port the planner already retired and settle
  typed, exactly as when the deadline cannot fund a retry. Factories that
  return a new port behave as before.
- The readiness proof asserts the refused retry and adds a real-subprocess
  case for the retry itself; the planner proof adds one case per retry branch.
- Carries the #672 strict-typecheck fix for the gateway-chat adapter proof
  (the same change as #675's 3acb2a0) so CI reaches the full regression.

Fixes #672
Refs #660
@Danceiny
Danceiny merged commit bb5e81e into main Oct 28, 2026
8 checks passed
@Danceiny
Danceiny deleted the claude/gotry-issue-674-afe827 branch October 28, 2026 06:36
Danceiny added a commit that referenced this pull request Oct 28, 2026
…e writer (#677)

The founder merged the A0 proposal (#675) and directed development to start with no per-question override, so Q1–Q7 stand as recommended; the owning authorities change together as the RFC's same-commit rule requires. Docs only, nothing changes at runtime.

Refs #674

Co-authored-by: huangzhen.0505 <huangzhen.0505@bytedance.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant