diff --git a/docs/operations/code-review-11-disposition.md b/docs/operations/code-review-11-disposition.md new file mode 100644 index 00000000..bd196ad9 --- /dev/null +++ b/docs/operations/code-review-11-disposition.md @@ -0,0 +1,40 @@ +# CodeRabbit Review 11 Disposition + +**Promotion PR:** [#11](https://github.com/DatabreezeService/databreeze-platform/pull/11) + +**Review run:** `8cc266ad-874b-4781-a97d-ebe86b0eb521` + +**Completed at (UTC):** 2026-08-02T09:28:06Z + +**Invocation policy:** This was the one permitted full CodeRabbit review for PR #11. No second review will be requested. + +## Valid issues fixed + +The following ten valid issues (nine inline comments plus one task-conditional nitpick) were reproduced against the reviewed `dev` commit and are being fixed in focused commits before promotion: + +1. The Luna bootstrap prompt now makes PostgreSQL migration/tenant tests conditional on durable-state changes and client coverage conditional on client behavior. +2. The evidence record stores the full source commit SHA while retaining the short display prefix. +3. The rollback note explains that reverting the reconciliation test removes `repo:check` enforcement and requires a fresh check. +4. Parallel-lane guidance now keeps CRF/PDA and MR/DQG serial by default and requires explicit interface-level control records before any overlap. +5. Android and Python normalized-key transformations are defined deterministically with examples. +6. The orchestration state section separates requirement states from plan/task states and includes all ledger vocabulary transitions. +7. The handoff record captures the CodeRabbit invocation timestamp in UTC. +8. Redis-loss recovery now fences stale workers and reconciles durable leases/effect receipts before redispatch. +9. Worktree instructions now select `feat/`, `fix/`, `docs/`, `ci/`, or another conventional prefix based on task type. +10. The orchestration path validator rejects backslashes, dot segments, parent segments, and resolved paths outside the repository root. + +The review grouped the first item as a nitpick and the remaining items as inline comments; all are recorded here because they affect the safety contract. + +## Rejected issues with evidence + +### Duplicate plan catalog + +CodeRabbit suggested moving the plan catalog out of `tools/repo-cli/src/check-execution-orchestration.mjs` and importing it from the test. The test intentionally keeps an independent expected catalog: it is the oracle that detects a checker or ledger silently dropping, reordering, or recounting a plan. Sharing the same map would allow the checker and test to drift together and would remove that protection. The current duplication is therefore deliberate and documented; no code change is made. + +### Docstring coverage warning + +The walkthrough reported a 0% docstring-coverage warning. Docstring coverage is not a repository check, release gate, or requirement in this project. The affected files are executable CLI/checker code and Markdown evidence, and adding decorative docstrings would not improve the validated behavior. The repository’s actual gates—format, lint, typecheck, contract parity, tests, builds, scans, Android checks, and infrastructure static checks—remain the acceptance evidence. + +## Verification + +Valid fixes must pass targeted tests, `corepack pnpm repo:check`, `corepack pnpm repo:build`, and the hosted checks on the follow-up `dev` PR. This document is evidence of the rejected comments and must remain in the promotion diff; it does not claim that a second CodeRabbit review occurred. diff --git a/docs/operations/foundation-reconciliation-2026-08-02.md b/docs/operations/foundation-reconciliation-2026-08-02.md new file mode 100644 index 00000000..0f393ff2 --- /dev/null +++ b/docs/operations/foundation-reconciliation-2026-08-02.md @@ -0,0 +1,68 @@ +# Engineering Foundation Reconciliation + +**Evidence date:** 2026-08-02 + +**Source commit:** `86e72d8569057d2a14ed6bb1672ce6a573fa8d7c` (display prefix: `86e72d8`) + +**Scope:** the merged engineering-foundation implementation and the 23 tasks in `docs/plans/010-engineering-foundation.md`. + +**Requirement status:** no requirement promoted to `verified`; the foundation plan supplies only the partial coverage explicitly recorded in `docs/plans/requirement-traceability.json`. + +## Reconciliation method + +This record was created from the current merged `dev` checkpoint, not from an earlier model report. Each task was matched to its repository paths, tests, generated artifacts, operational documentation, and release boundary. A task is marked `reconciled` only when its repository evidence is present and the applicable fresh command passes. A task with an unavailable external tool remains `reconciled-with-limit` and cannot promote a production or infrastructure requirement. + +## Task outcomes + +| Task | Outcome | Evidence boundary | +|---|---|---| +| Task 1 | reconciled | Root workspace, runtime pins, package discovery, and clean bootstrap are present and covered by repository checks. | +| Task 2 | reconciled | Dependency-boundary checker and allowed/rejected fixture tests pass through the root lint gate. | +| Task 3 | reconciled | Requirement parser/index, duplicate/gap fixtures, and the 611-record checked index pass. | +| Task 4 | reconciled | Versioned base schemas, validation fixtures, and generated envelope checks pass. | +| Task 5 | reconciled | TypeScript, Kotlin, and Python generated outputs are current and parity-tested. | +| Task 6 | reconciled | Compatibility policy and 28-case cross-runtime fixture parity pass. | +| Task 7 | reconciled | Permission/tenant primitives and narrowing tests are present; persistence remains owned by later IAM work. | +| Task 8 | reconciled | Typed configuration and provider-port packages are present with public API/build tests. | +| Task 9 | reconciled | Vietnamese-first and English-complete catalogs, negotiation, formatting, and completeness tests pass. | +| Task 10 | reconciled | Three canonical DataBreeze assets and checksum gates are present; bytes remain immutable. | +| Task 11 | reconciled | Deterministic Web/Desktop/Android derivative generation, source provenance, and visual/geometry gates pass. | +| Task 12 | reconciled | Shared design tokens, CSS/TypeScript/Android outputs, contrast, reduced-motion, and drift tests pass. | +| Task 13 | reconciled | Web shell, bilingual routing, governed navigation, error boundary, accessibility, and test/build gates pass. | +| Task 14 | reconciled | Fastify API shell, readiness, correlation, Problem Details, OpenAPI, Prisma schema inventory, and tests pass. | +| Task 15 | reconciled | Electron main/preload/renderer shell, context isolation, CSP/navigation policy, and IPC boundary tests pass. | +| Task 16 | reconciled | Python `uv` project, typed action registry, framed entry points, deterministic processor, and engine checks/build pass. | +| Task 17 | reconciled | Kotlin/Compose shell, generated resources, Room/WorkManager/Keystore ports, network security, backup policy, and debug unit tests pass. | +| Task 18 | reconciled | PostgreSQL/Redis/MinIO/Mailpit/OpenTelemetry Compose definitions, health checks, and static readiness checks pass; live Docker startup is separately environment-gated. | +| Task 19 | reconciled-with-limit | AWS OpenTofu modules, alpha composition, encryption/private-network/OIDC source checks, and non-applying infrastructure check pass; OpenTofu itself is not installed locally, so format/validate remain hosted-check obligations. | +| Task 20 | reconciled | Content-safe telemetry package, correlation propagation, redaction allowlists, and hostile-attribute tests are present and covered by repository checks. | +| Task 21 | reconciled | Path-aware quality/security/release workflows, pinned actions, least-privilege permissions, SBOM/provenance, and scan definitions are present and hosted checks pass. | +| Task 22 | reconciled | Development, deployment, rollback, secret-rotation, provider-adapter, release-channel, support, and local-infrastructure runbooks are present. | +| Task 23 | reconciled | This clean-checkout record is backed by the fresh verification commands below and contains no runtime artifacts, credentials, or customer data. | + +## Fresh verification evidence + +The following commands were run from a clean worktree at source commit `86e72d8` after locked dependency bootstrap: + +| Command | Result | +|---|---| +| `corepack pnpm install --frozen-lockfile` | Pass; lockfile and all 15 workspace projects installed. | +| `uv sync --locked --offline` in `services/engine` | Pass; locked Python 3.13 environment created. | +| `corepack pnpm repo:check` | Pass; formatting, lint, typecheck, orchestration/requirements/contract checks, repository CLI tests, and all workspace tests passed. | +| `corepack pnpm repo:build` | Pass; API, Web, Desktop, shared packages, and Python engine builds passed. | +| `apps/android/gradlew :app:testDebugUnitTest --no-daemon` from `apps/android` with the existing SDK path supplied | Pass; 27 Android debug unit-test tasks completed. | +| `corepack pnpm infra:check` | Pass; static AWS/local infrastructure checks passed without applying resources. | +| `git diff --check` | Pass; no whitespace errors. | + +The repository checks include generated-contract drift, brand checksum/derivative drift, dependency boundaries, 28-case TypeScript/Python/Kotlin parity, scan policy, and the orchestration checker. The Web bundle emits its existing chunk-size advisory while remaining inside the enforced gzip budget. + +## Known environment limits + +- OpenTofu is not installed on this workstation. No AWS infrastructure was applied; hosted CI must run the pinned OpenTofu format/validate checks before an infrastructure PR is accepted. +- Docker is installed but live local dependency startup was not required for this reconciliation. Run `corepack pnpm local:smoke` on a healthy Docker daemon before dogfood acceptance. +- Android instrumentation/emulator testing and signed release packaging remain Plan 400 gates; the debug unit suite passed with the local SDK path supplied through `ANDROID_HOME`/`ANDROID_SDK_ROOT`. +- No customer data or credentials were used. Ignored dependency caches, virtual environments, build output, and Gradle state remain untracked. + +## Release and rollback decision + +FND-001 is complete as an evidence-reconciliation task. Plan 010 remains `partial-needs-reconciliation` until FND-002 through FND-007 close their independent gates and hosted OpenTofu validation is available. The next orchestration task is `FND-002`. Reverting this record and its test removes the reconciliation evidence and its `repo:check` enforcement; after such a rollback, run `corepack pnpm repo:check` and record the resulting gap before merging. The rollback does not alter application code, generated contracts, migrations, assets, or runtime state. diff --git a/docs/plans/000-platform-program.md b/docs/plans/000-platform-program.md index 481621d2..2811f164 100644 --- a/docs/plans/000-platform-program.md +++ b/docs/plans/000-platform-program.md @@ -48,9 +48,11 @@ docs/plans/requirement-traceability.json records all 611 IDs with requested trac - `main` contains stable releases. `dev` is the integration branch. - New capabilities use `feat/`; corrections use `fix/`; operational and documentation work use conventional prefixes when more accurate. - Commit one coherent tested unit at a time. Do not combine unrelated applications or domains merely to reduce commit count. -- Pull requests target `dev`, normally contain 30–50 commits, and must not exceed 70 commits. -- Invoke CodeRabbit once per pull request after the branch is ready for review. Validate every comment against the specifications and tests; fix valid findings and document why invalid findings are not applied. -- Promote `dev` to `main` only through a separate release pull request after the relevant production gates pass. +- Feature/fix pull requests target `dev`, preferably contain 30–50 commits, and must not exceed 60 commits. Run local and hosted checks, but do not invoke CodeRabbit on these integration pull requests. +- Merge a green integration pull request while preserving its atomic rollback commits, then immediately open a separate `dev` → `main` promotion pull request for that completed batch. +- Invoke CodeRabbit exactly once on the otherwise-ready promotion pull request and request a full review. Do not invoke it if the promotion exceeds 280 changed files; split or revert the batch first. +- Reproduce every CodeRabbit claim against the reviewed commit. Fix valid findings in focused commits, document rejected findings with evidence, rerun all affected gates, and never request a second CodeRabbit review on that pull request. +- Do not merge a promotion when the single review was skipped, timed out, has unresolved valid findings, or required hosted checks are not green. ## Cross-cutting definition of done diff --git a/docs/plans/002-complete-execution-orchestration.md b/docs/plans/002-complete-execution-orchestration.md new file mode 100644 index 00000000..fd7cc544 --- /dev/null +++ b/docs/plans/002-complete-execution-orchestration.md @@ -0,0 +1,875 @@ +# Complete Platform Execution and Luna Handoff Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended when delegation is authorized) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Finish all 611 DataBreeze requirements through dependency-ordered, independently reversible tasks and preserve enough verified state that a new model can resume without guessing. + +**Architecture:** The numbered child plans remain the requirement owners. This document adds the execution DAG, atomic task boundaries, parallel-work rules, cross-plan gates, failure handling, and handoff contract that bind those child plans into one program. `execution-orchestration.json` is the machine-readable control record; `requirement-traceability.json` remains the requirement-to-code-and-evidence authority. + +**Tech Stack:** pnpm/Turborepo and strict TypeScript, NestJS/Fastify, PostgreSQL 17 with Prisma, Redis 7.4, S3-compatible storage, Electron, Kotlin/Compose, Python 3.13, OpenAPI/JSON Schema, OpenTofu/AWS Singapore, GitHub Actions, and CodeRabbit. + +## Global Constraints + +- Preserve the DataBreeze name and the three checksum-pinned legacy logo sources; generated assets may resize or crop only through the approved reproducible pipeline. +- Keep one monorepo with independently buildable Web, Windows Desktop, Android, API, and Python engine deployables. +- PostgreSQL is authoritative. Redis is disposable and must never become the only source of jobs, quotas, cursors, locks, or delivery state. +- Every repository query and mutation carries exact organization/workspace/project scope. A caller-supplied identifier never expands authority. +- Local mode sends no source paths, original bytes, previews, OCR text, source values, or reconstructable chunks to the cloud. Hybrid sends only policy-approved payload classes. +- Originals, evidence coordinates, recipes, rules, processors, datasets, reports, results, approvals, and releases are immutable versions. Corrections create successors. +- Workers and devices accept signed, typed, allowlisted actions only. They never receive database credentials, remote shell commands, arbitrary scripts, or unrestricted filesystem paths. +- Vietnamese is the complete default locale and English is complete. Partial fallback copy is a release failure. +- P0 is the production-capable gate, P1 completes GA, and the 13 P2 requirements remain disabled until plan 500. +- No requirement becomes `verified` until linked tests pass, evidence paths exist, restoration/rollback obligations are satisfied, and the applicable release gate approves it. +- Preserve unrelated user changes. Never commit credentials, customer data, runtime databases, generated reports, Office lock files, or local tool state. + +--- + +## 1. Authority and status semantics + +Read sources in this order when they disagree: + +1. `AGENTS.md` and current user instructions. +2. Accepted ADRs under `docs/decisions/`. +3. Normative requirements under `docs/specs/` and `docs/specs/requirement-index.json`. +4. Product and architecture documents under `docs/product/` and `docs/architecture/`. +5. The requirement-owning child plan under `docs/plans/`. +6. This orchestration plan and `execution-orchestration.json`. +7. Existing code and historical implementation reports. + +Code is evidence of work, not evidence of full requirement completion. Use these states consistently: + +| State | Meaning | Allowed next state | +|---|---|---| +| `planned` | No accepted implementation evidence has been reconciled. | `partial` or `implemented` | +| `partial` | Some behavior exists, but at least one implementation obligation remains. | `implemented`, or `planned` after an invalid implementation is removed through a reviewed change | +| `implemented` | The complete scoped behavior and tests exist, but cross-platform, security, recovery, or release evidence is incomplete. | `verified` or `partial` after a discovered gap | +| `verified` | All requirement-linked tests and release evidence pass at an immutable commit. | `released` in a release manifest | +| `released` | A coordinated signed release contains the verified requirement. | A later version; never silently reverted in the ledger | +| `blocked` | External authority or state is required after safe alternatives are exhausted. | `planned` or `partial` after the blocker is resolved | + +The ledger also uses these plan/task states; they are not requirement statuses and must not be copied into a requirement record: + +| Plan/task state | Meaning | Allowed next state | +|---|---|---| +| `partial-needs-reconciliation` | Existing code or historical evidence exists, but the current checkpoint still needs an explicit reconciliation task. | `in-progress`, `planned`, or `blocked` | +| `in-progress` | The selected task is actively being delivered on one branch/worktree. | `implemented`, `verified`, or `blocked` | +| `post-ga-planned` | An opt-in P2 plan is intentionally held until GA release. | `in-progress` after GA, or `blocked` | + +Never infer `verified` from a merged PR, a green unit test, file existence, or a previous model's prose. + +## 2. Recorded checkpoint + +This plan was prepared on 2026-08-02 from remote `dev` at `b21642b` and remote `main` at `8ac8bca`; promotion PR 8 had merged and no PR was open. The requirement manifest contained 611 records: 444 P0, 154 P1, 13 P2; 608 were `planned` and 3 were `partial`. + +Merged PRs 1–8 establish substantial engineering, IAM/AUD/BUA, IAE/DSM, JRA, and DSO code. Plans 010–050 must therefore start with evidence reconciliation, not blind reimplementation. Plans 060–500 remain unverified and must be treated as planned until their gates pass. + +The hashes above are an audit anchor, not a branch lock. Every session must fetch and recompute live state; update the ledger checkpoint only as part of a committed task/PR handoff so session-local observations do not create meaningless dirty files. + +## 3. Execution dependency graph + +```mermaid +flowchart TD + A["010 Foundation reconciliation"] --> B["020 IAM / AUD / BUA completion"] + B --> C["030 IAE / DSM completion"] + C --> D["040 JRA processing and approvals"] + D --> E["050 Devices, sync, and offline"] + E --> F["060 Collaboration and integrations"] + F --> G["070 Three-platform dogfood"] + G --> H1["100 Folder Autopilot"] + H1 --> H2["110 Spreadsheet Auditor"] + G --> H3["120 Quote Intelligence"] + G --> H4["130 Operations Capture"] + H3 --> I1["200 Invoice Leak Detector"] + H2 --> I2["210 Client Report Factory"] + H3 --> I2 + H4 --> I3["220 Private Data Analyst"] + I2 --> I3 + I3 --> J1["300 Migration Ready"] + I1 --> J2["310 Data Quality Guard"] + J1 --> J2 + F --> J3["320 Embedded Importer"] + E --> J3 + J1 --> K["400 Production readiness and GA"] + J2 --> K + J3 --> K + K --> L["500 Post-GA P2 extensions"] +``` + +Parallel execution is allowed only when all of these are true: + +- Dependency nodes are verified for the interfaces consumed by both tasks. +- Branches do not edit the same Prisma schema, canonical contract, migration order, shared export map, or generated artifact. +- Each branch owns disjoint requirement IDs and a disjoint primary feature directory. +- One integration owner resolves contract/migration ordering before either branch merges. +- The combined `dev` to `main` promotion remains below 280 changed files, leaving margin under CodeRabbit's 300-file limit. + +Safe parallel lanes after dogfood are FA→SA, QI, and OC. CRF/PDA and MR/DQG remain serial by default. EI may overlap with those later plans only when both control records declare the matching interface-level entry gates, contract/migration reservations, and integration owner; otherwise they remain serial too. The foundation spine 010→070 stays serial. + +## 4. Repository path contract + +Every feature uses these exact roots; use the module key in the final column rather than the prose plan name. + +| Plan | API feature and Prisma schema | Web/Desktop/Android/engine key | +|---|---|---| +| 020 | `services/api/src/features/{iam,aud,bua}` and `services/api/prisma/schema/{iam,aud,bua}.prisma` | `identity`, `audit`, `entitlements` | +| 030 | `services/api/src/features/{iae,dsm}` and `services/api/prisma/schema/{iae,dsm}.prisma` | `artifacts`, `datasets` | +| 040 | `services/api/src/features/jra` and `services/api/prisma/schema/jra.prisma` | `jobs` | +| 050 | `services/api/src/features/dso` and `services/api/prisma/schema/dso.prisma` | `devices` | +| 060 | `services/api/src/features/{nco,int}` and `services/api/prisma/schema/{nco,int}.prisma` | `collaboration`, `integrations` | +| 100 | `services/api/src/features/fa` and `services/api/prisma/schema/fa.prisma` | `folder-autopilot` | +| 110 | `services/api/src/features/sa` and `services/api/prisma/schema/sa.prisma` | `spreadsheet-auditor` | +| 120 | `services/api/src/features/qi` and `services/api/prisma/schema/qi.prisma` | `quote-intelligence` | +| 130 | `services/api/src/features/oc` and `services/api/prisma/schema/oc.prisma` | `operations-capture` | +| 200 | `services/api/src/features/ild` and `services/api/prisma/schema/ild.prisma` | `invoice-leak-detector` | +| 210 | `services/api/src/features/crf` and `services/api/prisma/schema/crf.prisma` | `client-report-factory` | +| 220 | `services/api/src/features/pda` and `services/api/prisma/schema/pda.prisma` | `private-data-analyst` | +| 300 | `services/api/src/features/mr` and `services/api/prisma/schema/mr.prisma` | `migration-ready` | +| 310 | `services/api/src/features/dqg` and `services/api/prisma/schema/dqg.prisma` | `data-quality-guard` | +| 320 | `services/api/src/features/ei` and `services/api/prisma/schema/ei.prisma` | `embedded-importer` | + +Feature clients live under `apps/web/src/features/` and `apps/desktop/src/features/`. Android package directories use the deterministic `android-key`; engine processor directories use the deterministic `python-key`: + +| Derived key | Transformation | Example | +|---|---|---| +| `android-key` | Start with the lowercase ASCII module key, replace separators (`-` and `_`) with boundaries, remove all non-alphanumeric characters, and require the first character to be a letter. | `folder-autopilot` → `folderautopilot`; `private-data-analyst` → `privatedataanalyst` | +| `python-key` | Start with the lowercase ASCII module key, replace every separator or invalid character with one underscore, collapse repeated underscores, and require the first character to be a letter. | `folder-autopilot` → `folder_autopilot`; `private-data-analyst` → `private_data_analyst` | + +Thus Android paths are `apps/android/app/src/main/kotlin/com/databreeze/` and deterministic processors are `services/engine/src/databreeze_engine/processors/`. Canonical schemas live under `packages/contracts/schemas/v1/`; pure domain types live under `packages/domain/src//v1.ts`. Do not create aggregate prose-named modules such as `identity-audit-entitlements` or `production-readiness` in application code. + +## 5. Atomic task execution contract + +Every task ID below uses the same non-negotiable loop: + +Task IDs are orchestration batches, not one-to-one requirement IDs even when they share a domain prefix. The child plan and traceability manifest remain authoritative for the individual requirements owned by each batch. + +- [ ] Read the owning specification sections, exact requirement rows, accepted ADRs, dependency interfaces, and existing tests before editing. +- [ ] Create a short-lived `feat/` or `fix/` branch from the live integration branch in an ignored worktree; verify a clean baseline. +- [ ] Add or revise canonical OpenAPI/JSON Schema first when the public interface changes; run `corepack pnpm contracts:check` and record the expected red drift or failing consumer test. +- [ ] Add a requirement-linked failing domain/policy/state-machine test. The failure must prove missing behavior, not a fixture or compilation mistake. +- [ ] Add a centrally ordered migration and real PostgreSQL repository test before persistence implementation. Use expand→migrate→verify→contract; rollback uses a forward compensating migration. +- [ ] Implement domain then application then adapter then API/client behavior through published ports. Cross-foundation coordination belongs under `services/api/src/orchestration`. +- [ ] Add content-safe telemetry, timeout/cancellation behavior, idempotency, recovery, and rollback evidence in the same task. +- [ ] Run the narrow test, the owning package tests, `corepack pnpm repo:check`, and `corepack pnpm repo:build`. +- [ ] Update `requirement-traceability.json` only for IDs actually evidenced; update `execution-orchestration.json` with the immutable commit and next task. +- [ ] Commit one reversible outcome. A task may have several commits when contract, domain, migration, adapter, client, or verification outcomes are independently reversible. + +Expected commands at every task boundary: + +```powershell +git status --short --branch +corepack pnpm contracts:check +corepack pnpm --filter @databreeze/domain test +corepack pnpm --filter @databreeze/api test +corepack pnpm repo:check +corepack pnpm repo:build +git diff --check +``` + +Android tasks additionally run `apps/android/gradlew.bat test` and the applicable instrumentation suite. Engine tasks run `uv sync --locked --offline`, `uv run pytest`, `uv run ruff check .`, and `uv run mypy src`. Web/Desktop interaction tasks run the applicable Vitest and Playwright suites. + +## 6. Foundation and dogfood task catalog + +### Plan 010 — Engineering foundation reconciliation + +#### FND-001 — Reconcile merged foundation evidence + +Audit Tasks 1–23 in `010-engineering-foundation.md` against code, tests, runbooks, and PRs 1–3. Record missing evidence without marking requirements verified. Test clean checkout, generated-contract drift, brand hashes, dependency boundaries, and all five deployable builds. + +#### FND-002 — Close Android shell gaps + +Verify Compose navigation, Room, WorkManager, Keystore, bilingual resources, network security, backup exclusions, generated contracts/tokens, instrumentation smoke, process death, account isolation, and supported API levels under `apps/android`. + +#### FND-003 — Close local infrastructure gaps + +Verify pinned PostgreSQL 17, Redis 7.4, MinIO, Mailpit, and OpenTelemetry health checks, credential-free bootstrap, module-schema creation, non-destructive start/stop/reset commands, port collisions, missing Docker, disk pressure, and restart persistence under `infrastructure/local`. + +#### FND-004 — Close portable AWS foundation gaps + +Validate, without applying, OpenTofu networking, CloudFront/S3, ECS API/workers, RDS, ElastiCache, KMS, Secrets Manager, logs, and GitHub OIDC in `ap-southeast-1`. Test plan-time validation, least privilege, private subnets, encryption, secret indirection, provider pinning, and destroy protection. + +#### FND-005 — Close telemetry and diagnostics gaps + +Verify correlation propagation and allowlisted records across TypeScript, Kotlin, and Python. Test secrets, paths, source values, evidence excerpts, exception messages, high-cardinality identifiers, malformed trace headers, and provider causes are dropped. + +#### FND-006 — Close CI and supply-chain gaps + +Verify path-aware jobs, pinned actions, least-privilege tokens, contract drift, SBOM, license/secret/SAST/container scans, provenance, protected release environments, fork safety, and failure on missing outputs. + +#### FND-007 — Publish foundation reconciliation evidence + +Update development/deployment/rollback/secret/provider/support runbooks, traceability, and a clean-checkout evidence record. Keep every unresolved item partial and make the next foundation plan executable from a clean clone. + +### Plan 020 — Identity, audit, and entitlements + +#### IAM-001 — Tenant transaction and authority base + +Complete module schemas, tenant-scoped repository bases, application transaction context, authorization/security epochs, and atomic mutation-plus-audit behavior. Test sibling tenants, ancestor/descendant scope, rollback, stale epoch, missing context, and concurrent writes. + +#### IAM-002 — Credentials, sessions, CSRF, and PKCE + +Complete Argon2id credentials, verification/recovery challenges, personal-organization bootstrap, 15-minute access sessions, rotating single-use refresh families, reuse detection, CSRF, and system-browser PKCE. Test normalization, timing-safe failures, stolen refresh races, redirect mismatch, verifier replay, session fixation, and clock skew. + +#### IAM-003 — Organizations, workspaces, projects, and roles + +Complete organization/workspace/project lifecycle, memberships, six role bundles, deny-by-default authorization, ancestry checks, and project narrowing. Test last-owner invariants, bulk changes, deleted parents, stale cached authority, vertical privilege escalation, and every resource family's horizontal isolation. + +#### IAM-004 — Invitations, MFA, recovery, and ownership + +Complete invitations, ownership transfer, TOTP/WebAuthn ports, recovery codes, step-up assertions, and account recovery. Test expired/consumed invitations, factor replacement, recovery-code reuse, lost-factor recovery, step-up expiry, self-approval boundaries, and two owners racing to leave. + +#### IAM-005 — Service and device identities + +Complete IAM-owned service accounts and device identities, proof-of-possession enrollment, activation, key rotation, permanent revocation, epochs, and signed offline authorization snapshots. Test cloned keys, replaced devices, reinstall, revoked snapshots, stale clocks, and unavailable authority. + +#### AUD-001 — Immutable action registry and append ledger + +Complete the closed action registry, per-scope sequences, safe summaries, idempotent transactional append, privileged-access audit, and signed offline-fragment acceptance/quarantine. Test sequence contention, replay with changed content, unsafe summary keys, cross-scope fragments, missing signatures, and transaction rollback. + +#### AUD-002 — Audit seals, retention, export, and restoration + +Complete Merkle seals, independent signed seal storage, verification, legal holds, retention classes, signed JSONL/CSV export, restoration verification, and administration. Test tampered leaves/roots, missing ranges, seal-key rotation, export truncation, hold conflicts, and restore to a clean database. + +#### BUA-001 — Plans, subscriptions, entitlements, and offline leases + +Complete immutable plan versions, provider-independent subscriptions, entitlement snapshots, quotas, signed offline leases, and stable admission reason codes. Test plan supersession, suspension, clock skew, revoked leases, feature downgrade, and provider absence. + +#### BUA-002 — Reservation and append-only usage accounting + +Complete quota reservation, append-only usage ledgers, concurrency control, correction entries, reconciliation, export, and suspension preservation through `ExecutionAdmissionCoordinator`. Test double reservation, finalize/release races, negative corrections, lost dispatch, and inherited organization quotas. + +#### IAM-006 — Security and administration clients + +Build complete Web organization/session/MFA/device/audit/entitlement administration and focused Desktop/Android session/device security views with complete Vietnamese/English copy, keyboard/TalkBack behavior, and no client-side authority assumptions. + +#### IAM-007 — Identity/audit/entitlement release proof + +Run tenant-escape, token-family race, MFA expiry, last-owner, audit immutability, seal tamper, entitlement race, backup/restore, accessibility, performance, and fail-closed provider tests. Update only requirement records with exact evidence. + +### Plan 030 — Artifacts, evidence, datasets, and definitions + +#### IAE-001 — Immutable artifact and dataset records + +Add artifact, artifact-version, placement, inbox, evidence, lineage, retention, dataset, schema, mapping, rule, metric, and reference-entity records in the owning module schemas with tenant keys, revisions, hashes, and immutable publication identifiers. + +#### IAE-002 — Cloud multipart intake and quarantine + +Implement multipart intake with size/hash/media verification, immutable object keys, resumable parts, malware scan states, idempotent finalization, quarantine, and job-bound grants. Test aborted parts, digest mismatch, content-type spoofing, duplicate finalization, scan timeout, archive traversal, decompression bombs, and object-store retry. + +#### IAE-003 — Local and Hybrid intake registration + +Implement Desktop/Android registration through opaque placements. Prove Local never sends paths, bytes, previews, OCR, values, or reconstructable chunks; Hybrid sends only approved classes. Test path-like handles, symlinks, source replacement, device offline, and policy narrowing mid-transfer. + +#### IAE-004 — Evidence resolution and preview grants + +Implement typed coordinates, exact-version resolution, device-open descriptors, `SOURCE_OFFLINE`, scoped preview grants, and coordinate lineage. Test stale evidence, hidden/renamed sheets, removed pages, revoked devices, expired grants, and sibling-tenant hashes. + +#### IAE-005 — Derivation, staleness, retention, and deletion + +Implement correction/derived versions, source-change staleness, manifests, legal-hold-aware retention, authoritative deletion eligibility, and verified cloud deletion. Test shared placements, failed object deletion, restore-before-delete, conflicting holds, and immutable lineage. + +#### DSM-001 — Governed datasets and semantic definitions + +Complete immutable datasets/versions, schema compatibility, semantic definitions, metrics, canonical parties, and immutable merge/split history. Test missing versus null, incompatible field changes, unit/grain mismatch, merge cycles, and stale publications. + +#### DSM-002 — Deterministic mappings, rules, and drift + +Complete mapping/rule registries, typed transformations, compatibility/drift review, and publication. Reject executable code, non-determinism, unbounded expressions, duplicate targets, locale-sensitive ambiguity, and changed reference bundles. + +#### DSM-003 — Profiling, validation, quality gates, and lineage + +Implement deterministic profiling/validation, findings, reproducible lineage, governed exports, and local/cloud parity. Test malformed encodings, formula injection, large cardinalities, invalid dates/currencies, resource limits, and partial outcomes. + +#### IAE-006 — Artifact and dataset clients + +Build Web Inbox/catalog/evidence/governance screens, Desktop local evidence navigation, Android capture/share intake, and complete Vietnamese/English empty/offline/error/conflict states without exposing local paths to Web. + +#### IAE-007 — Artifact/dataset release proof + +Run hostile upload, cross-tenant, source-change, retention/deletion, recovery, parity, accessibility, and performance suites. Verify exact content immutability and publish evidence per requirement. + +### Plan 040 — Jobs, processing, findings, reviews, and approvals + +#### JRA-001 — Canonical job and review state machines + +Complete recipe, job, step, attempt, lease, checkpoint, result, effect receipt, finding, review, and approval schemas/state machines with immutable versions and optimistic revisions. + +#### JRA-002 — Typed actions and signed recipe publication + +Complete action manifests, risk/effect classes, handler/schema digests, triggers, compatibility validation, resource bounds, data modes, and signed recipe envelopes. Reject arbitrary scripts, shell commands, unknown schemas, expired signatures, and digest drift. + +#### JRA-003 — Atomic execution admission + +Complete `ExecutionAdmissionCoordinator` so authorization, IAE inputs, DSM definitions, DSO routing, BUA reservation, JRA creation, AUD append, and outbox insertion commit atomically. Test every dependency rejection and rollback point. + +#### JRA-004 — Authoritative scheduling and dispatch recovery + +Implement PostgreSQL-authoritative scheduling, Redis hints, outbox delivery, lost-message reconstruction, leases, heartbeats, progress, and stale-attempt rejection. Test Redis loss, duplicate delivery, scheduler failover, clock skew, and lease contention. + +#### JRA-005 — Authenticated cloud worker execution + +Implement internal worker APIs and job-bound object grants without database credentials. Test grant expiry, worker impersonation, changed inputs, network partitions, resource exhaustion, and result-schema mismatch. + +#### JRA-006 — Desktop sidecar execution boundary + +Implement signed-envelope verification, attempt-scoped handles, encrypted temporary workspaces, framed bounded JSON-RPC, supervision, provisional offline execution, reconnect acceptance/quarantine, and cleanup. Test crashes, oversized frames, traversal, stale approvals, revoked devices, and disk-full cleanup. + +#### JRA-007 — Canonical findings and review queues + +Complete actionable findings, feature-owned diagnostic details, review tasks, immutable resolutions, evidence links, assignments, and authorization-safe transitions. Test deleted evidence, duplicate resolution, reassignment races, and unauthorized deep links. + +#### JRA-008 — Exact approvals and separation of duties + +Complete approval policies, subject/effect hashes, separation of duties, MFA, expiry, invalidation, and append-only decisions. Test self-approval, changed subjects, stale source, revoked approver, clock skew, and forged decision payloads. + +#### JRA-009 — Retry, cancellation, effects, and quota settlement + +Complete retry/cancellation/compensation, partial outcomes, effect idempotency, cleanup, quota finalization, and crash reconciliation. Test ambiguous external writes, cleanup failure, cancellation races, and stale workers. + +#### JRA-010 — Job/review/approval clients + +Build full Web queues and focused Desktop/Android progress, finding, review, and online approval surfaces with accessible Vietnamese/English states and no cached-authority decisions. + +#### JRA-011 — Processing release proof + +Run lost-message, worker-crash, stale-lease, duplicate-effect, changed-input, revocation, cleanup, parser-security, parity, performance, accessibility, and restoration suites. + +### Plan 050 — Devices, synchronization, and offline operation + +#### DSO-001 — Immutable workspace data-mode policy + +Complete signed Local/Hybrid/Cloud policy manifests with Hybrid default and narrowing-only descendants. Test stale policy, unauthorized broadening, revoked signatures, schema version mismatch, and policy changes during work. + +#### DSO-002 — Device capabilities, grants, health, and revocation + +Complete IAM-backed capabilities/grants, opaque folder handles, expected digests, health projections, key epochs, and immediate revocation. Test grant substitution, action escalation, path leakage, replaced folders, revoked keys, and unavailable IAM authority. + +#### DSO-003 — Change logs, snapshots, cursors, and resnapshot + +Complete workspace change logs, consistent snapshots, opaque scope-bound cursors, schema negotiation, epoch invalidation, tombstones, and resnapshot. Test cursor corruption, scope reduction/expansion, compaction gaps, reinstall, and server rollback. + +#### DSO-004 — Durable client mutations and explicit conflicts + +Complete encrypted dependency-aware mutation queues and typed conflicts without last-write-wins for protected state. Test replay, reordering, duplicates, dependency cycles, concurrent revisions, and conflict resolution retries. + +#### DSO-005 — Resumable blob transfer + +Complete chunked upload/download, hash verification, placement publication, retries, ranges, and abandoned-transfer cleanup. Test changed blobs, overlapping ranges, missing chunks, expiry, disk pressure, and cross-tenant transfer IDs. + +#### DSO-006 — Strict-Local user-carried packages + +Complete encrypted packages with exact signed manifests, recipient/passphrase envelopes, expiry, isolated import, placement lineage, receipts, and quarantine. Test wrong recipient, weak/truncated envelope, replay, tampering, expired package, and partial import. + +#### DSO-007 — Windows offline runtime + +Complete encrypted SQLite state, background sync, pause controls, watcher persistence, restart recovery, Windows-protected keys, and safe diagnostics. Test OS restart, database corruption, credential loss, long paths, case collisions, network shares, and updater rollback. + +#### DSO-008 — Android offline runtime + +Complete Room account/workspace isolation, WorkManager queues/constraints, Keystore identities, sign-out cleanup, scoped storage, share intents, and Local package export. Test process death, clock skew, revoked keys, permission changes, storage pressure, duplicate work, and reinstall. + +#### DSO-009 — Web device and conflict administration + +Build device, grant, health, conflict, data-location, and migration administration without revealing filesystem paths. Test stale UI state, removed administrators, accessible tables, and bilingual errors. + +#### DSO-010 — Sync/offline release proof + +Run interruption, replay, cursor, tombstone, device-loss, revocation, reinstall, disk-pressure, policy-expiry, content-leak, parity, performance, and recovery suites; reconcile DSO/DSK/AND evidence conservatively. + +### Plan 060 — Notifications, collaboration, public API, and integrations + +#### NCO-001 — Notification and collaboration records + +Add notification intent/delivery/preference, thread, comment, revision, mention, reaction, assignment, and tombstone records with tenant scope and stable anchors. + +#### NCO-002 — In-app notification delivery + +Implement outbox delivery, deterministic deduplication, SSE, polling fallback, read/archive state, quiet hours, mandatory notices, and digests. Test reconnect, duplicate outbox rows, preference races, removed users, and backpressure. + +#### NCO-003 — Comments, mentions, evidence anchors, and assignments + +Implement comments/revisions/tombstones, evidence anchors, mentions, reactions, resolution, assignments, and safe deep links. Test unauthorized mentions, revoked evidence, deleted entities, concurrent edits, and cross-tenant identifiers. + +#### NCO-004 — Replaceable email, push, and Desktop notifications + +Add SMTP/SES, FCM, Desktop local-notification, and polling adapters with minimized templates. Test provider outage, suppression, invalid tokens, credential rotation, locale/time-zone formatting, and mandatory-notice rules. + +#### INT-001 — Public API and service-account boundary + +Complete `/v1` service-account authentication, cursor/idempotency/rate-limit/problem conventions, capability discovery, versioning, and deprecation metadata. Test replay, stale cursors, rate-limit races, removed scopes, and downgrade behavior. + +#### INT-002 — Governed connector lifecycle + +Implement connector definitions/connections, encrypted credential references, capability drift, checkpoints, governed import/export, and degraded/reauthorization states. Test credential expiry, scope loss, provider schema drift, ambiguous writes, and provider exit. + +#### INT-003 — Signed outbound webhooks + +Implement durable minimal payloads, HMAC rotation overlap, replay protection, retries, delivery inspection, and manual replay. Test SSRF, DNS rebinding, redirects, private addresses, clock skew, secret rollover, and receiver outage. + +#### INT-004 — Verified inbound callbacks and reconciliation + +Implement signature/timestamp/replay checks, durable inboxes, normalized failures, idempotent processing, and reconciliation. Test duplicate/out-of-order callbacks, missing provider events, forged timestamps, and ambiguous terminal states. + +#### NCO-005 — Collaboration and integration clients + +Build complete Web administration and focused Desktop/Android notification/collaboration views with safe deep links, bilingual copy, accessibility, and offline/read-state reconciliation. + +#### INT-005 — Collaboration/integration release proof + +Run mention authorization, removed-user, webhook replay/SSRF/DNS, credential rotation, provider outage, backlog recovery, rate-limit, tenant-escape, accessibility, and provider-exit tests. + +### Plan 070 — Three-platform dogfood walking skeleton + +#### DOG-001 — Licensed deterministic acceptance fixtures + +Create synthetic Vietnamese workbooks and a cross-runtime harness with fixed hashes, formulas, encodings, dates, currencies, hidden sheets, malformed inputs, and explicit licensing/provenance. + +#### DOG-002 — Desktop folder enrollment and exactly-once intake + +Enroll Desktop, grant one opaque folder capability, stabilize/hash a workbook, and register exactly one Local artifact without cloud path or bytes. Test partial writes, locks, rename storms, duplicate watcher events, restart, symlinks, and source replacement. + +#### DOG-003 — Read-only local spreadsheet audit + +Run inventory, formula-family and anomaly processing locally with exact sheet/cell evidence. Disable macros, add-ins, queries, links, and external execution. Test corrupt/huge workbooks, unsupported formulas, 1900/1904 dates, and locale separators. + +#### DOG-004 — Hybrid-minimal synchronization + +Synchronize only policy-approved metadata, findings, coordinates, job state, and bounded excerpts. Prove the cloud cannot reconstruct the workbook and rejects broader payloads after policy narrowing. + +#### DOG-005 — Web review and Android exact approval + +Review on Web and approve/reject the exact repair-plan hash on Android with online authority and MFA. Test stale plans, changed evidence, revoked approvers, duplicate decisions, and offline approval attempts. + +#### DOG-006 — Safe derivative and undo receipt + +Validate against an isolated copy, recheck source/capability/policy/approval, create a separately named derivative, and persist effect/undo receipts. Test collisions, disk full, antivirus locks, source changes, compensation, and undo conflicts. + +#### DOG-007 — Dogfood chaos and acceptance record + +Prove network loss, restart, duplicate delivery, Redis loss, changed source, stale approval, and device revocation never duplicate effects or mutate the original. Publish one release record covering all ten dogfood acceptance conditions. + +### Plan 100 — Folder Autopilot + +**Requirement owner:** `100-folder-autopilot.md` (34 requirements). **Entry gate:** DOG-007 accepted. **Exit gate:** governed file actions are previewable, approval-bound, idempotent, reversible where declared, and incapable of escaping an opaque folder capability. + +#### FA-001 — Folder bindings and assignments + +Model Autopilot bindings as projections over DSO grants and JRA recipe versions. Add tenant-scoped contracts, migrations, repository tests, and authorization checks for create, pause, rebind, retire, and revoked-folder behavior. + +#### FA-002 — Recipe preview, validation, and routing + +Implement bounded previews, schema/capability validation, deterministic matcher priority, collision/resource estimates, confidence review, and routing to registered processors only. Reject ambiguous matches, unsupported effects, missing placement, and stale recipes before a job is admitted. + +#### FA-003 — Stable watchers and reconciliation + +Complete Windows watcher persistence, periodic reconciliation scans, content-hash deduplication, deterministic matching, and output-lineage recursion prevention. Test partial writes, exclusive locks, rename storms, network-share disconnects, junction/symlink escape, case-insensitive aliases, clock skew, and restart between observation and registration. + +#### FA-004 — Staged actions, compensation, and undo + +Implement constrained rename/copy/move/convert actions through typed sidecar handles. Stage outputs, revalidate digest/capability/policy, fsync where supported, commit atomically where possible, journal effects, and expose explicit compensation/undo conflicts. Test disk full, antivirus locks, destination replacement, cross-volume moves, name collisions, and crash at each boundary. + +#### FA-005 — Findings, review, approval, and exact execution + +Project diagnostics into canonical JRA findings/reviews, hash the exact proposed effect, apply risk-specific approval policy, and recheck source, device, grant, policy, recipe, and approval immediately before execution. Reject stale approvals and duplicate/replayed effect attempts. + +#### FA-006 — Autopilot clients + +Build Web authoring/monitoring, Desktop execution/evidence/health, and Android alert/approval/pause views. Include Vietnamese/English parity, accessible error recovery, safe diagnostics, and zero disclosure of local paths outside the enrolled Desktop. + +#### FA-007 — Autopilot scale and release proof + +Add bounded bulk operations, concurrency/throughput controls, redacted execution export, folder-health dashboards, soak tests, interruption recovery, tenant-escape tests, and release evidence for FA P0/P1 requirements. + +### Plan 110 — Spreadsheet Auditor + +**Requirement owner:** `110-spreadsheet-auditor.md` (27 requirements). **Entry gate:** DOG-007 accepted. **Exit gate:** audits and repairs are deterministic, evidence-addressable, macro-safe, and never mutate the original workbook. + +#### SA-001 — Safe workbook inventory + +Implement bounded XLSX/XLS/CSV inventory and parsing with macros, add-ins, queries, external links, and external execution disabled. Record supported/unsupported features without evaluating them. Test corrupt ZIP/XML, encrypted files, hidden and very-hidden sheets, merged cells, shared formulas, locale formats, and resource limits. + +#### SA-002 — Formula families and anomaly detection + +Normalize formula families and detect outliers, gaps, overwrites, broken ranges, and inconsistent references with exact workbook/sheet/cell coordinates. Handle 1900/1904 date systems, array/dynamic formulas, unsupported functions, and cached-value disagreement explicitly. + +#### SA-003 — Profiles, rules, findings, and suppressions + +Bind immutable DSM audit profiles and deterministic rules to canonical JRA findings/reviews. Preserve immutable diagnostic details, comparison baselines, suppression scope/expiry/reason, and evidence version. Prevent a suppression from hiding new rule or source versions silently. + +#### SA-004 — Exact repair proposals and validation + +Define allowlisted repair operations, before/after diffs, isolated-copy validation, selective acceptance, plan hashes, stale-plan rejection, and derived output registration. Test formula injection, changed source, unsupported calculation, overlapping repairs, validation failure, and crash before/after output publication. + +#### SA-005 — Recurrence and evidence clients + +Add recurring folder audits, Web triage/trends, Desktop safe local evidence navigation, and focused Android review. Preserve Local/Hybrid constraints and display `SOURCE_OFFLINE` rather than substituting newer or unauthorized content. + +#### SA-006 — Governed audit reports + +Generate HTML, PDF, JSON, and XLSX reports containing immutable manifest IDs and evidence references. Escape spreadsheet formulas in exports, disclose incomplete calculations, and verify renderer/version reproducibility with golden fixtures. + +#### SA-007 — Auditor safety and release proof + +Prove malicious-workbook containment, decompression and XML bounds, large-workbook budgets, local/cloud result parity, original immutability, bilingual/accessibility completion, recovery, and all SA P0/P1 evidence. + +### Plan 120 — Quote Intelligence + +**Requirement owner:** `120-quote-intelligence.md` (27 requirements). **Entry gate:** DOG-007 accepted. **Exit gate:** every comparison value has source evidence or an explicit missing-input state, and no vendor API is required. + +#### QI-001 — RFQ, quote, and business-party model + +Implement RFQ requirements, comparisons, immutable quote versions, supplier/customer bindings through DSM reference entities, correction lineage, tenant isolation, and source-version pinning. + +#### QI-002 — Document and scan extraction + +Add bounded PDF/image/DOCX/XLSX/CSV extraction with local Tesseract OCR for scans, normalized candidates, confidence, and exact evidence. Test rotated/low-resolution scans, Vietnamese diacritics, multi-page tables, password protection, malformed office archives, and OCR timeout/fallback. + +#### QI-003 — Normalization and line matching + +Implement versioned unit, pack-size, currency, tax, and date normalization plus exact/tolerance/partial/split/merge/unmatched workflows. Require review for ambiguous mappings and preserve override history. Test inconsistent units, aliases, missing rates, inclusive/exclusive tax, and duplicate lines. + +#### QI-004 — Landed cost, scenarios, and eligibility + +Implement deterministic landed-cost calculations, rate sources/effective dates, rounding policy, freight/duty/tax components, missing-input states, scenarios, scores, and eligibility gates. Property-test currency conversion, rounding, zero/negative values, and incomplete comparisons. + +#### QI-005 — Review, approval, and immutable release + +Implement questions, overrides, canonical review/approval, exact comparison hashes, superseded-quote detection, immutable release, and safe comparison copying. Changed source, assumptions, rates, or formulas invalidate approval. + +#### QI-006 — Quote clients + +Build Web comparison workspaces, Desktop batch/local evidence tools, and Android scan/share/correction/approval flows with offline capture but online consequential approval, bilingual copy, and accessible tables. + +#### QI-007 — Decision packs and release proof + +Generate XLSX/PDF/Web decision packs with evidence manifests; add comparison history, duplicate/superseded detection, performance/parity fixtures, tenant/security tests, and QI P0/P1 release evidence. + +### Plan 130 — Operations Capture + +**Requirement owner:** `130-operations-capture.md` (40 requirements). **Entry gate:** DOG-007 accepted. **Exit gate:** field work survives process/network failure, preserves operator values, and synchronizes immutable submissions exactly once. + +#### OC-001 — Versioned form definitions + +Implement stable field IDs, immutable form versions, declarative visibility/calculation logic, validation, compatibility diffs, and Web/Android previews. Reject cycles, nondeterministic expressions, incompatible published changes, and executable customization. + +#### OC-002 — Assignments and offline bundles + +Implement assignments, checksummed reference bundles, availability windows, retention/offline policy, authorization epochs, and pinned definition delivery. Handle clock skew, expired assignments, policy narrowing, missing references, and bundle corruption deterministically. + +#### OC-003 — Native Android capture + +Implement text/numeric/choice/repeating fields, CameraX document/photo capture, barcode/QR, voice, signature, consented location, permissions, and immutable media placement. Test permission revocation, activity/process death, orientation, font scaling, low storage, background limits, and consent withdrawal. + +#### OC-004 — Drafts, submission, and resumable sync + +Implement encrypted autosaved drafts, local validation, immutable submission versions, idempotent mutation IDs, resumable attachments, durable acknowledgement, and safe sign-out isolation. Test duplicate taps, app reinstall, interrupted upload, changed form revision, revoked device, and server receipt lost after commit. + +#### OC-005 — OCR/transcription candidates and corrections + +Store OCR/transcription as confidence-bearing candidates with evidence; never overwrite operator values. Corrections create versions with actor/reason lineage. Test conflicting candidates, unsupported language, partial media, provider timeout, and offline local processing. + +#### OC-006 — Supervision, returns, and approval + +Implement canonical reviews, returns, correction requests, approval facades, comments, mentions, and notifications. Preserve submitted history, prevent self-approval where policy forbids it, and invalidate decisions after material correction. + +#### OC-007 — Desktop scanner reconciliation + +Implement scanner-folder intake, deterministic assignment/submission matching, ambiguity queues, duplicate handling, batch evidence, and reconciliation. Test repeated scans, filename reuse, partial files, clock mismatch, unreadable media, and cross-workspace collision. + +#### OC-008 — Capture exports and release proof + +Add governed exports/module intake, admin limits, storage/sync health, Web supervision, accessibility, process-death/reinstall scenarios, local/cloud parity, performance budgets, and OC P0/P1 release evidence. + +### Plan 200 — Invoice Leak Detector + +**Requirement owner:** `200-invoice-leak-detector.md` (27 requirements). **Entry gate:** QI-007 complete. **Exit gate:** deterministic invoice findings are evidence-backed and categorically cannot pay or contact suppliers. + +#### ILD-001 — Invoice and governing-document model + +Implement immutable invoices, contracts, amendments, rate cards, purchase orders, receipts, DSM supplier bindings, effective periods, version lineage, and tenant-scoped repository/migration tests. + +#### ILD-002 — Invoice extraction and evidence + +Reuse bounded document/OCR ports for header and line extraction with confidence and exact evidence. Test credit notes, multi-page tables, rotated scans, duplicated pages, locale numbers/dates, malformed files, and local/cloud parity. + +#### ILD-003 — Candidate matching and allocation + +Implement deterministic invoice-to-document candidates, one-to-many allocations, conflicts, low-confidence review, and immutable manual override history. Prevent over-allocation, stale match reuse, and silent matching across supplier/business-unit boundaries. + +#### ILD-004 — Expected-charge calculations + +Implement effective-dated rates, discounts, fees, freight, tax, periods, caps, conversions, receipts, and explicit incomplete states. Property-test partial receipts, amendments, rate gaps/overlap, multi-currency, rounding, negative adjustments, and tax-inclusive terms. + +#### ILD-005 — Findings and amount categories + +Store immutable leak details linked to canonical findings/reviews and separate exposure, validated, disputed, recovered, and dismissed amounts. A status change never rewrites the original calculation or evidence. + +#### ILD-006 — Cases and approval-bound evidence packages + +Implement cases, redaction preview, exact approval hashes, immutable closure, and evidence packages. Enforce in contracts and effects that the module cannot initiate payment, mutate accounting systems, or contact suppliers. + +#### ILD-007 — Leak clients and release proof + +Build Web investigations/dashboards, Desktop local batches, Android capture/review, recurring intake, exports, performance fixtures, duplicate/superseded invoice tests, tenant/security recovery tests, and ILD P0/P1 evidence. + +### Plan 210 — Client Report Factory + +**Requirement owner:** `210-client-report-factory.md` (27 requirements). **Entry gates:** SA-007 and QI-007. **Exit gate:** every published output is reproducible, evidence-linked, format-specific, reviewed, and revocable where shared. + +#### CRF-001 — Templates, definitions, and renderer capabilities + +Implement immutable templates, report definitions, stable block IDs, dataset/schema/metric bindings, parameters, locales, brands, and versioned renderer capability declarations. Reject unsupported block/format combinations before execution. + +#### CRF-002 — Deterministic preflight + +Validate tenant scope, schema compatibility, data freshness/quality, evidence availability, parameter completeness, renderer support, and output policy. Produce explicit blocked/warning states without silently omitting failed content. + +#### CRF-003 — Evidence-linked tables, charts, and metrics + +Render deterministic tables/charts/metrics from governed definitions and record value-to-evidence lineage. Test sorting/ties, nulls, units, locales, chart accessibility, overly large result sets, and schema drift. + +#### CRF-004 — Multi-format rendering + +Implement HTML/Web, Chromium PDF, DOCX, PPTX, and XLSX renderer adapters with isolated temporary workspaces and per-format result states. Use golden visual/structural fixtures for fonts, page breaks, charts, time zones, renderer upgrades, and partial format failure. + +#### CRF-005 — Report review, approval, and release + +Implement immutable report versions, stable block comments, material-change hashes, canonical approval, release policy, and immutable output manifests. Any material template, dataset, evidence, parameter, or renderer change invalidates approval. + +#### CRF-006 — Revocable Web sharing + +Implement expiring/revocable share grants, authentication/download policy, viewer auditing, content security headers, and source-access isolation. Test leaked links, removed users, revocation races, clock skew, crawler previews, and attachment caching. + +#### CRF-007 — Scheduling, clients, and release proof + +Add schedules, tenant/client-isolated batches, cloning, Desktop rendering, Android review, retry/rollback, complete Web administration, parity/performance/accessibility tests, and CRF P0/P1 evidence. + +### Plan 220 — Private Data Analyst + +**Requirement owner:** `220-private-data-analyst.md` (37 requirements). **Entry gates:** OC-008 and CRF-007. **Exit gate:** numeric truth is deterministic and reproducible; optional AI can propose but never fabricate or execute truth. + +#### PDA-001 — Governed analysis bindings + +Implement analysis dataset/semantic bindings over DSM definitions, relationships, metrics, compatibility diffs, policy, freshness, and quality validation. Reject ambiguous grain, unit, ownership, and relationship definitions. + +#### PDA-002 — Typed analysis plan AST + +Define a versioned, bounded AST for projections, filters, joins, aggregates, comparisons, shares, cohorts, sorting, and supported statistics. Generate all runtime models and reject unknown nodes, unbounded joins, executable expressions, and schema/version mismatch. + +#### PDA-003 — Vietnamese/English question interpretation + +Implement question intake, ambiguity prompts, explicit assumptions, editable governed plans, and Android transcript confirmation. Preserve the original question and chosen interpretation. Never imply certainty when multiple grains, units, dates, or entities match. + +#### PDA-004 — Deterministic execution + +Compile the validated AST to Polars/DuckDB with row/column/time/memory limits, permissions, cardinality estimates, grain/unit checks, and quality gates. Test join explosion, integer/decimal precision, time zones, division by zero, unsupported statistics, cancellation, and disk pressure. + +#### PDA-005 — Results, provenance, and non-answers + +Persist immutable result/provenance manifests, evidence drill-down, coverage/freshness disclosure, stable non-answer reasons, accessible tables, and valid chart selection. Results without source support state `UNSUPPORTED_BY_SOURCE` rather than inventing a value. + +#### PDA-006 — Saved, certified, and scheduled analyses + +Implement saved plans, frozen-versus-rerun behavior, parameters, sharing, JRA certification, schedules, and blocked occurrences. Changed definitions, permissions, data quality, or parameters visibly invalidate or block certification. + +#### PDA-007 — Optional AI planning boundary + +Add disabled-by-default local/provider-neutral adapters that may propose an AST or narrative over already computed facts. Enforce egress policy, prompt minimization, provider timeout/exit, schema validation, explanation labels, and deterministic re-execution; never accept provider numbers as truth. + +#### PDA-008 — Analyst clients and release proof + +Build Web/Desktop/Android surfaces, snapshot comparison, report embedding, governed exports, egress administration, bilingual/accessibility flows, adversarial prompt tests, local/cloud parity, and PDA P0/P1 evidence. + +### Plan 300 — Migration Ready + +**Requirement owner:** `300-migration-ready.md` (32 requirements). **Entry gate:** PDA-008 complete. **Exit gate:** export-first migration packages reconcile exactly; no destination write occurs without a separately reviewed adapter. + +#### MR-001 — Migration projects and sources + +Implement migration projects, immutable source versions, parsing profiles, capacity policy, and explicit Desktop grants. Test encoding/BOM/delimiter variance, malformed rows, archive limits, Local/Hybrid placement, and changed source during intake. + +#### MR-002 — Profiling, target schema, and mapping + +Bind DSM target schemas, mappings, rules, lookups, and immutable plans with compatibility validation. Surface locale dates/numbers, missing/null distinctions, unknown columns, duplicate keys, target drift, and destructive mappings before a run. + +#### MR-003 — Cleaning, duplicate review, and survivorship + +Implement deterministic cleaning/normalization, duplicate blocking/matching, survivorship rules, exact evidence, and ambiguous-cluster review. Property-test stable ordering, transitive clusters, conflicting identifiers, Unicode normalization, and override history. + +#### MR-004 — Dry runs, dispositions, and exceptions + +Implement dry runs, per-row dispositions, corrections, exception review, comparisons, and immutable output candidates. Reprocessing the same input/plan is deterministic and does not reuse stale exception decisions. + +#### MR-005 — Reconciliation and approval + +Implement count/control-total reconciliation, release gates, separation-of-duties approval, source/plan hashes, and stale-source blocking. Test partial rows, aggregation precision, late corrections, mismatched totals, duplicate approval, and revoked approvers. + +#### MR-006 — Export-first release packages + +Generate UTF-8 CSV/JSON plus optional Parquet/JSONL, rejected rows, checksums, manifests, reason summaries, and stable ordering. Neutralize spreadsheet formula injection and prove package verification/recovery without destination effects. + +#### MR-007 — Incremental migration and release proof + +Add incremental batches, migration books, Desktop/cloud parity, Web administration, Android review, performance/security/recovery tests, and MR P0/P1 evidence. The base module cannot accept arbitrary destination commands or credentials. + +### Plan 310 — Data Quality Guard + +**Requirement owner:** `310-data-quality-guard.md` (35 requirements). **Entry gates:** ILD-007 and MR-007. **Exit gate:** monitored quality failures, repairs, waivers, and scores are versioned, explainable, evidence-backed, and replayable. + +#### DQG-001 — Quality contracts and policy + +Implement DSM-backed dataset bindings, immutable quality contracts, ownership, fitness, incident, and waiver policy with activation validation. Reject incomplete ownership, incompatible schemas, unbounded rules, and policy cycles. + +#### DQG-002 — Deterministic rules and reconciliation + +Implement schema/value/reference/cross-field rules plus count/sum/balance/group reconciliation with typed outcomes and evidence. Property-test null/missing distinctions, decimals, Unicode, time zones, duplicate keys, and partial datasets. + +#### DQG-003 — Baselines and drift + +Implement versioned baselines and volume/schema/category/numeric/null/freshness drift. Address seasonality, low sample size, baseline poisoning, categorical churn, schema evolution, and backfilled observations explicitly. + +#### DQG-004 — Monitors and exact runs + +Implement schedules/triggers, late-arrival policy, run manifests, deterministic/statistical states, idempotent occurrences, and backpressure. Test overlapping schedules, clock/DST changes, late partitions, restart, Redis loss, and source version changes. + +#### DQG-005 — Findings, incidents, and escalation + +Project immutable details into canonical findings/reviews, group incidents deterministically, escalate by policy, and notify without storms. Test regrouping, repeated failures, removed owners, quiet hours, redaction, and incident reopen behavior. + +#### DQG-006 — Repairs and verified closure + +Implement typed repair proposals, bounded previews, canonical approval, derived datasets, verification runs, and verified closure. Never alter source versions; reject stale approvals and preserve failed repair attempts/effects. + +#### DQG-007 — Waivers, scorecards, and signed reports + +Implement time-bound waivers, compensating controls, visible waived failures, scorecards, trends, backfills, and signed evidence reports. Test expiry during a run, overlapping waivers, retroactive edits, score denominator changes, and signature verification. + +#### DQG-008 — Quality clients and release proof + +Build Web governance, Desktop local repair/evidence, Android incident/approval, scale/parity/recovery/accessibility tests, and DQG P0/P1 evidence. + +### Plan 320 — Embedded Importer + +**Requirement owner:** `320-embedded-importer.md` (27 requirements). **Entry gates:** DSO-010 and INT-005. This plan may run parallel to Plans 100–310 after its entry gates. **Exit gate:** hostile embed/upload tests pass and all local access remains outbound-only, signed, scoped, and non-programmable. + +#### EI-001 — Customer partitions and environments + +Implement tenant-isolated customer partitions, sandbox/production environments, DSM schema bindings, limits, credentials, and support visibility. Prove no partition/environment/resource ID can escape tenant ancestry. + +#### EI-002 — Hosted session and browser boundary + +Implement short-lived hosted sessions, exact origin/frame/message restrictions, CSP, localization, accessibility, tokenized theming, and no executable customization. Test origin confusion, wildcard subdomains, clickjacking, postMessage forgery, expired sessions, referrer leakage, and third-party cookie loss. + +#### EI-003 — Upload, mapping, and correction + +Implement resumable bounded uploads, immutable sources, DSM mapping, structured validation issues, correction overlays, and virus/archive/formula protections. Test upload bombs, malformed office files, interrupted parts, stale schemas, duplicate files, and client retry after server commit. + +#### EI-004 — Idempotent import commit + +Implement accepted/rejected/skipped accounting, consequential approval, asynchronous JRA status, downloadable errors, immutable result manifests, and idempotent commits. Replays return the original outcome and cannot duplicate downstream rows. + +#### EI-005 — Service accounts and webhooks + +Use IAM service-account credentials and INT-owned subscriptions, delivery history, rotation, and replay. Test leaked/rotated secrets, signed replay, DNS rebinding, provider downtime, customer endpoint slowness, and customer deletion. + +#### EI-006 — Outbound-only Desktop local gateway + +Implement signed typed jobs, DSO grants, approved schemas, bounded object handles, and Android safe-status alerts. Reject arbitrary paths, commands, scripts, inbound listeners, unsigned jobs, expired grants, and result exfiltration beyond data-mode policy. + +#### EI-007 — Importer clients and release proof + +Add admin/support/usage/policy views, SDK integration harness, branding, local/cloud parity, hostile embed/upload/gateway tests, accessibility/performance checks, and EI P0/P1 evidence without adding a third-party runtime. + +### Plan 400 — Production readiness and GA + +**Requirement owner:** `400-production-readiness.md` (23 requirements). **Entry gates:** MR-007, DQG-008, and EI-007. **Exit gate:** all P0/P1 records are verified with durable evidence, coordinated artifacts are signed, restoration and rollback are exercised, and no critical/high security finding remains. + +#### GA-001 — Reviewed AWS environments + +Provision alpha, staging, and production in `ap-southeast-1` through reviewed OpenTofu: CloudFront/S3 Web, at least two ECS API tasks, worker pools, RDS HA/PITR, ElastiCache, KMS, Secrets Manager, versioned buckets, private networking, budgets, and GitHub OIDC. Apply only from protected environments with recorded plans and drift detection. + +#### GA-002 — Runtime and supply-chain hardening + +Harden non-root containers, read-only filesystems where possible, capabilities, egress, job-bound object grants, secret injection/rotation, image signing, SBOMs, provenance, pinned dependencies, and regional recovery configuration. Test expired/rotated credentials and registry/provider unavailability. + +#### GA-003 — Database, object, and regional recovery + +Exercise expand/migrate/verify/contract migrations, five-minute-or-better regional RPO, four-hour RTO, point-in-time restore, object-version recovery, audit/seal verification, and quarterly restoration records. Cover partial migrations, schema skew, bad backfills, KMS access loss, and restore to isolated accounts. + +#### GA-004 — Capacity, latency, and SLO proof + +Load-test API latency, admission, sync, worker throughput, storage, webhooks, provider adapters, and backpressure against published budgets and 99.9% objectives. Establish saturation signals, queue limits, degradation modes, cost guards, and noisy-neighbor/tenant fairness tests. + +#### GA-005 — Signed Windows release + +Package and code-sign the installer, executables, sidecar, update manifest, and packages. Prove clean install, upgrade, interrupted update, corrupted signature, downgrade rejection, rollback, revocation, least privilege, Windows Defender compatibility, and retained encrypted state. + +#### GA-006 — Signed Android release + +Produce signed internal/closed builds, protect signing keys, test supported API levels, backup exclusions, exported components, deep links, scoped storage, WorkManager recovery, startup/scroll/capture macrobenchmarks, staged rollout, crash thresholds, halt, and rollback-forward procedures. + +#### GA-007 — Security assessment and finding closure + +Complete threat models, horizontal/vertical tenant escape, parser fuzz/abuse, archive/XML/formula/macro attacks, SSRF/DNS/webhook, IPC/RPC, Android intents/storage, dependency/container/secret scans, and independent assessment. Track every finding; no critical/high finding may be waived into release. + +#### GA-008 — Operations, alerts, and kill switches + +Add content-safe SLO dashboards/alerts, processor/provider/connector kill switches, incident response, time-bound support access, device revocation, capacity, regional/provider outage, and customer communication runbooks. Drill false-positive alerts and kill-switch recovery. + +#### GA-009 — Provider-independent billing readiness + +Keep production on Free/Development/Admin-granted immutable plan versions and entitlements unless a separate approved ADR enables commercial billing. Prove suspension, overage, corrections, export, reconciliation, and preserved customer access to mandated data/audit functions without payment-provider dependence. + +#### GA-010 — Privacy, accessibility, localization, and support + +Complete export/deletion/retention/legal-hold flows, safe support diagnostics, Vietnamese/English catalog parity, WCAG 2.2 AA, Desktop keyboard/screen reader/scaling, Android TalkBack/font/touch targets, consent notices, and customer-facing data-location/mode guidance. + +#### GA-011 — Failure and rollback drills + +Run release halt, API/worker rollback, Redis loss, database failover, object recovery, identity-provider independence, email/push/OCR/AI outage, Desktop updater rollback, Android rollout halt, device compromise/revocation, sync rebuild, and provider-exit drills. Record owners, timestamps, measured RPO/RTO, defects, and remediation. + +#### GA-012 — Coordinated GA release + +Validate every P0/P1 trace record is `verified`, paths and evidence exist, checks are green from a clean checkout, migrations/feature flags are ordered, artifacts have checksums/provenance, restoration is current, support is staffed, and rollback targets are usable. Publish one signed release manifest linking Web/API/worker/Desktop/Android/engine/contracts/database versions; mark records `released` only after observed rollout gates pass. + +### Plan 500 — Post-GA P2 extensions + +**Requirement owner:** `500-post-ga-extensions.md` (13 requirements). **Entry gate:** GA-012 released. **Exit gate:** every extension is opt-in, disabled by default, independently revocable, provider-exitable, and unable to execute arbitrary customer code. + +#### P2-001 — Sanitized cross-workspace draft packs + +Implement DSM-024, FA-035, and OC-041 as versioned export/import drafts with explicit field allowlists, origin provenance, compatibility review, tenant-safe identifier remapping, secret/content stripping, and no automatic activation. Test malicious packs, schema collisions, old versions, local-content leakage, and partial import rollback. + +#### P2-002 — Optional AI suggestions and explanations + +Implement SA-028, QI-028, ILD-028, CRF-028, PDA-038, DQG-036, and EI-028 through the same provider-neutral/local boundary. Require egress policy, minimized inputs, output schemas, labels, evidence-backed deterministic verification, cost/rate limits, provider kill switch, deletion/retention handling, and a complete non-AI path. + +#### P2-003 — Declarative destination adapters + +Implement MR-033 using reviewed versioned manifests, approved fields/effects, job-bound credentials, dry-run/reconciliation, exact approval, idempotency, checkpoints, compensation, and provider-exit export. No arbitrary destination code, SQL, shell, or undocumented endpoint is allowed. + +#### P2-004 — Generated SDKs and connector program + +Implement INT-023 and INT-024 with generated versioned SDKs, conformance fixtures, signed connector packages, sandboxing, declared scopes/egress/resources, review/revocation, compatibility windows, telemetry minimization, and incident response. Third-party code never runs inside the API, Desktop renderer, Android process, or unrestricted customer filesystem context. + +## Cross-plan verification matrix + +Before a plan may move from `planned` or `partial-needs-reconciliation` to `verified`, its owner must attach all applicable evidence below to every owned requirement record: + +| Boundary | Mandatory evidence | Failure that blocks promotion | +|---|---|---| +| Contracts | Canonical schema diff, generated TypeScript/Kotlin/Python parity, compatibility result | Drift, unversioned breaking change, hand-edited generated output | +| Database | Ordered migration, real PostgreSQL transaction/tenant tests, recovery or compensating rollback | Cross-module table read, unscoped query, destructive irreversible backfill | +| Domain | Unit/property/state-machine tests with stable reason codes | Nondeterministic outcome, implicit last-write-wins, mutable history | +| Runtime | Adapter integration, retry/idempotency/crash tests, resource bounds | Arbitrary shell/path access, database credentials in worker, Redis authority | +| Privacy | Local/Hybrid/Cloud negative tests and telemetry snapshot | Path, secret, source bytes, or reconstructable content crosses policy | +| Security | Horizontal/vertical tenant escape and attack-family coverage | Unresolved critical/high finding or authorization inferred from UI/cache | +| Clients | Web/Desktop/Android scope, offline behavior, bilingual and accessibility evidence | Partial locale, inaccessible consequential flow, offline privilege escalation | +| Operations | Metrics/alerts/runbook/rollback and safe diagnostics | Content-bearing telemetry, absent kill/recovery path, unverifiable restoration | + +## Stop conditions and escalation + +Stop the active task without widening scope when any of these occurs: authoritative specs conflict; a migration would destroy non-reconstructable data; an action requires new vendor/business authorization; signing or production credentials are missing; user-owned dirty changes overlap the task; a security boundary cannot fail closed; or a required test cannot be made deterministic. Record the exact blocker, preserved state, attempted safe alternatives, and the smallest decision needed. Difficulty, test duration, and a large remaining roadmap are not blockers. + +## Definition of complete + +The program is complete only after GA-012 is released and, when post-GA scope is requested, P2-004 is verified. A merged branch, green unit test, created UI, or requirement marked `implemented` is not equivalent to `verified` or `released`. The authoritative count remains 611 requirements: 444 P0, 154 P1, and 13 P2. diff --git a/docs/plans/003-luna-handoff-runbook.md b/docs/plans/003-luna-handoff-runbook.md new file mode 100644 index 00000000..b9b3c579 --- /dev/null +++ b/docs/plans/003-luna-handoff-runbook.md @@ -0,0 +1,177 @@ +# Luna Handoff and Resume Runbook + +Use this runbook to resume DataBreeze after a model, machine, branch, or hosted-check transition. It is intentionally conservative: historical chat is context, while fetched Git state, committed plans, traceability, tests, and release evidence are authority. + +## Start-of-session algorithm + +1. Locate the canonical `databreeze-platform` repository; do not implement in the legacy `Databreeze` directory. +2. Read repository `AGENTS.md` files, `docs/plans/README.md`, `002-complete-execution-orchestration.md`, `execution-orchestration.json`, the selected child plan, and the requirement records it owns. +3. Fetch before trusting any recorded hash: + + ```powershell + git fetch --all --prune + git status --short --branch + git branch --show-current + git rev-parse HEAD + git rev-parse origin/dev + git rev-parse origin/main + gh pr list --state open --limit 100 --json number,title,headRefName,baseRefName,isDraft,statusCheckRollup,url + ``` + +4. Run `corepack pnpm orchestration:check`. Treat `execution-orchestration.json.checkpoint` as historical only; recompute the live PR/branch state. +5. Inspect the selected task's requirement records. A record marked `implemented`, `verified`, or `released` must have real code/test/evidence paths that exist and match the current commit. Downgrade an unsupported status in the same corrective commit; never preserve a false completion claim. +6. If a clean checkout is required, create an ignored worktree from the current integration base. Select the branch prefix from the task type (`feat` for capability work, `fix` for corrections, `docs` for documentation, `ci` for workflow-only work, or another conventional prefix recorded in the task). Never reuse a worktree with unrelated user changes: + + ```powershell + git check-ignore -q .worktrees + git worktree add .worktrees/ -b / origin/dev + ``` + +7. Bootstrap exactly as repository documentation specifies. The known clean-checkout sequence is: + + ```powershell + corepack pnpm install --frozen-lockfile + Push-Location services/engine + uv sync --locked --offline + Pop-Location + corepack pnpm repo:check + ``` + + If the offline Python cache is unavailable, use the documented online locked sync; do not alter the lock merely to make bootstrap pass. +8. Select `nextTaskId` only if every dependency is verified and no open PR or dirty worktree already owns it. Otherwise follow the table below and record the corrected next task. +9. State the selected task, assumptions, entry gate, expected files, tests, and stop conditions before mutation. If delegation is explicitly authorized, assign only disjoint paths with explicit integration ownership. + +## Resume-state decision table + +| Observed state | Required action | Forbidden shortcut | +|---|---|---| +| Open `dev` → `main` promotion PR awaiting its first CodeRabbit review | Resume that PR, wait for the one full review, validate comments, and complete or block it before new promotion work | Opening a second promotion PR or invoking CodeRabbit twice | +| Promotion PR has one CodeRabbit review with unresolved comments | Reproduce each claim, fix valid findings on focused `fix/*` commits, document rejected claims, rerun checks, then merge when policy passes | Blindly accepting/rejecting comments or requesting another review | +| Promotion PR review was skipped, cancelled, or timed out | Keep the PR open and wait or request user direction; record that the one allowed invocation was consumed if it was sent | Reinvoking on the same PR or merging without the required review | +| Open feature PR to `dev` | Resume hosted checks and merge it after green checks; do not request CodeRabbit there | Bypassing checks or moving CodeRabbit to the feature PR | +| Feature branch has unpushed commits | Verify them, push the same branch, and update/open its PR | Recreating or squashing away atomic rollback points without approval | +| Branch diverged from `origin/dev` | Fetch, inspect both sides, merge/rebase only if repository policy and conflict ownership are clear; retest the combined tree | Resetting, overwriting, or force-pushing user work | +| Dirty tree contains only the active task's known edits | Review the diff, run targeted checks, and continue or commit the smallest complete unit | Assuming uncommitted work is valid because it looks related | +| Dirty tree has unknown or overlapping user edits | Preserve it, inspect worktrees/branches, and work elsewhere; ask only if safe isolation is impossible | Stashing, deleting, resetting, or editing over unknown work | +| Ledger `nextTaskId` conflicts with Git/evidence | Trust fetched Git and evidence, reconcile the ledger in a focused commit, and record why | Starting both tasks or silently rewriting history | +| Dependency is only `implemented`, not `verified` | Finish its tests/evidence/review gate before the dependent task | Treating merged code as a verified dependency | +| Baseline fails before task edits | Diagnose and document whether environment or repository caused it; repair in a `fix/*` unit or stop if unsafe | Attributing the failure to the new task or weakening the gate | +| Migration/schema or generated-contract drift exists | Reconcile canonical sources, regeneration, migrations, and compatibility before feature work | Editing generated clients or database state manually | +| Required production/signing/business credential is unavailable | Complete all credential-independent code/tests/runbooks and stop at the explicit external gate | Using personal/untracked credentials or claiming release readiness | + +## Atomic task execution loop + +For each `#### TASK-ID —` item in `002-complete-execution-orchestration.md`: + +1. Confirm plan dependencies, requirement ownership, feature flag, data mode, tenant scope, migration order, rollback, and platform surfaces. +2. Change canonical OpenAPI/JSON Schema first and add a failing contract/generation test when the task changes an interface. +3. Add failing domain/state-machine/policy/property tests for happy, invalid, replay, concurrency, stale-revision, authorization, and data-mode cases. +4. Add an ordered migration plus real PostgreSQL tenant/transaction/outbox tests when durable state changes. Use expand/migrate/verify/contract; immutable history is corrected with versions or compensating records. +5. Implement domain and application behavior through published ports. Repositories require tenant/workspace scope. Foundations never import another foundation's persistence. +6. Add only the required adapters and client vertical slice. Desktop renderer receives no raw Node/filesystem power; worker has no database credentials; Android background work carries IDs/revisions rather than secrets/content. +7. Add content-safe telemetry, stable problems/reason codes, kill/failure behavior, recovery, and rollback notes. +8. Update every affected traceability record with exact existing paths. Status meanings are strict: + + - `planned`: no implementation evidence. + - `partial`: some behavior exists, but its gate is incomplete. + - `implemented`: code exists and scoped tests pass. + - `verified`: all required cross-platform/security/recovery evidence exists and passes at the recorded commit. + - `released`: verified artifacts passed the coordinated rollout gate. + +9. Run targeted tests first, then: + + ```powershell + corepack pnpm repo:check + corepack pnpm repo:build + git diff --check + git status --short + ``` + +10. Inspect generated/runtime debris before commit. Do not commit `.venv`, `node_modules`, Gradle state, build output, logs, caches, secrets, local databases, Terraform state, or test reports unless the repository explicitly tracks a sanitized fixture. +11. Commit one independently reversible outcome with a semantic message. Do not combine contracts, an unrelated fix, and a different feature just to increase commit count. +12. Push after each stable task boundary. Update the ledger/checkpoint only with verified facts and leave a handoff record if stopping. + +## Pull-request and CodeRabbit protocol + +1. Branch from current `origin/dev` using `feat/` or `fix/`. Keep atomic commits; preferred PR size is 30–50 commits and hard maximum is 60. Cut earlier at a coherent boundary when risk, dependency ordering, or reviewability warrants it. +2. Before a feature PR, ensure it targets `dev`, has no unrelated commits, and passes local gates. Open it with requirement/task/evidence/rollback notes. CodeRabbit must not be invoked on this PR. +3. Wait for hosted checks. Diagnose failures; do not merge red or missing required checks. Merge with history that preserves the atomic rollback units, normally `--no-ff`/merge commit rather than squash. +4. Immediately compare `dev` and `main`. If `dev` contains the reviewed batch and no incompatible promotion is open, create `dev` → `main`. If the diff exceeds 280 changed files, do not invoke CodeRabbit: split/revert the feature batch or request user direction first. +5. When the promotion PR is otherwise ready, invoke CodeRabbit exactly once with a full review request. Record the invocation URL/time. Do not invoke it on the feature PR and do not ask twice on the promotion PR. +6. Wait for the review. For each comment, reproduce the claimed behavior against the exact PR commit, classify it as valid/invalid/uncertain, and save the evidence. Use `superpowers:receiving-code-review` or the repository's CodeRabbit review skill when available. +7. Fix valid findings in focused `fix/*` commits or a focused promotion branch that is safely merged back through `dev`; ensure the promotion diff remains exactly `dev` → `main`. Document rejected comments with concise technical evidence. Do not request a second CodeRabbit pass. +8. Rerun targeted checks, `repo:check`, `repo:build`, and hosted checks after fixes. Human verification owns the final response to the one review. +9. Merge the promotion only when the single full review completed, valid findings are resolved, rejected findings are documented, required checks are green, branch protection permits it, and rollback remains known. +10. Update/fetch local `dev` and `main`, record merge hashes/PRs/release evidence, then create the next integration branch from the new `origin/dev`. + +## Edge-case response matrix + +| Edge case | Detection | Safe response | +|---|---|---| +| Original local file might be modified | Effect plan targets the source placement or source digest changed | Fail closed; operate on an isolated copy, create a derivative, and preserve the original hash | +| Local-mode content/path appears in cloud payload or telemetry | Contract/redaction snapshot or negative egress test fails | Kill dispatch/sync, quarantine the payload, rotate exposed secret if any, open a security finding, and do not retry broadly | +| Tenant scope is absent or ancestry is ambiguous | Repository/API test or runtime guard cannot prove scope | Deny the action; never infer scope from cached UI, IDs, hashes, or object keys | +| Device/user/grant is revoked while offline | Epoch/lease/grant check is expired or mismatched | Stop new work, quarantine provisional output, require online reauthorization, and preserve local audit evidence | +| Duplicate command/job/webhook/client mutation | Existing idempotency/effect receipt matches | Return the prior outcome; never repeat a consequential effect | +| Same idempotency key has different payload | Stored request hash differs | Return a stable conflict/security problem and audit it; do not choose either silently | +| Lease expires while a worker finishes | Attempt/lease revision is stale | Reject/quarantine the result, clean grants/temp state, and let authoritative scheduling decide retry | +| Redis is lost | Dispatch/cache/lock disappears | First reconcile durable attempts and leases, fence stale workers, and verify idempotency/effect receipts; then rebuild dispatch hints from PostgreSQL outbox/jobs and redispatch only eligible work. Redis is never authority. | +| Object store is partially available | Multipart/grant/hash operation fails | Keep state resumable, avoid finalization until verification, expire grants, and reconcile abandoned parts | +| Database migration fails halfway | Migration journal/verify stage fails | Stop deploy, use the rehearsed compatible rollback/compensation path, preserve immutable records, and restore only from verified recovery points | +| Contract generation differs by runtime | Drift/parity check fails | Fix canonical schema/generator/version, regenerate all runtimes, and block merge | +| Source changes after review/approval | Digest/version/effect hash differs | Invalidate the plan and approval; create a new proposal/review rather than substituting evidence | +| Offline conflict touches protected state | Base revision or policy changed | Create an explicit conflict record; never last-write-wins memberships, approvals, policies, definitions, or effects | +| Parser encounters macro/archive/XML bomb | Admission/resource limit or sandbox detects it | Quarantine, return a safe diagnostic, release resources, and never execute embedded content | +| Provider times out after a possible write | Outcome is ambiguous | Reconcile with provider checkpoint/idempotency before retry; surface degraded/unknown state | +| Email/push/OCR/AI provider fails | Adapter health/backlog rises | Preserve canonical intent/job, use documented polling/local fallback, and avoid making the provider authoritative | +| Webhook target resolves to private/reserved address | DNS/IP/redirect validation changes | Reject delivery, audit safe metadata, and never follow the redirect | +| Disk full/antivirus lock/crash during Desktop effect | Sidecar write/journal fails | Leave source untouched, preserve staging/journal, surface recovery, and retry only after exact revalidation | +| Android process dies mid-capture/sync | WorkManager/Room state is incomplete | Resume from durable IDs/revisions/parts; never duplicate submission or leave secrets in worker input | +| Windows/Android signing key missing or compromised | Release signing/verification gate fails | Halt release, rotate/revoke via runbook, rebuild from provenance, and never ship an unsigned stable artifact | +| CodeRabbit comment conflicts with specs/tests | Reproduction disproves claim | Document rejection with paths/tests; do not change code merely to satisfy the comment | +| CodeRabbit uncovers a systemic issue late in promotion | Reproduction shows issue spans prior commits | Block promotion, create focused fix tasks, preserve the one review record, and obtain user direction if a fresh PR/review is necessary | +| Commit or changed-file budget would be exceeded | Preflight count reaches threshold | Cut a coherent PR before the hard limit; if over 280 files before promotion review, split/revert the batch before invoking CodeRabbit | +| User sends stop/override instruction | New message replaces or pauses active scope | Reach a safe boundary, preserve work, record exact state, and stop; do not continue autonomously | + +## End-of-session handoff record + +Add a concise record to the task/PR description or a dated, tracked release-evidence file when material work is committed. Never store secrets or source content. + +```text +Observed at (UTC): +Canonical repository/worktree: +Branch / HEAD / upstream: +Remote dev / main: +Open feature PR / promotion PR: +CodeRabbit invocation count, invocation timestamp (UTC), and review URL: +Active plan / task ID: +Requirement IDs and statuses changed: +Completed commits (hash — outcome): +Checks run and exact results: +Migration / contract / feature-flag state: +Valid review findings fixed: +Review findings rejected with evidence: +Known failures or blockers: +Uncommitted files and ownership: +Safest next command: +Next task ID and entry gate: +Rollback points: +``` + +The record supplements Git; it cannot claim `verified` without traceable test/release evidence. If nothing was committed, state that explicitly and identify whether uncommitted files are safe to discard, preserve, or continue—never discard them automatically. + +## Luna bootstrap prompt + +Copy this into the first Luna session and replace only the bracketed values discovered from live Git: + +```text +You are resuming DataBreeze in the canonical databreeze-platform repository. Do not trust chat checkpoints until you fetch and verify Git/PR state. Read every applicable AGENTS.md plus docs/plans/README.md, docs/plans/002-complete-execution-orchestration.md, docs/plans/003-luna-handoff-runbook.md, docs/plans/execution-orchestration.json, the selected child plan, and its requirement-traceability records. + +Live verified checkpoint: branch [BRANCH], HEAD [HEAD], origin/dev [DEV], origin/main [MAIN], open feature PR [FEATURE_PR_OR_NONE], open dev→main promotion PR [PROMOTION_PR_OR_NONE]. Run the orchestration checker and the documented clean baseline before edits. Preserve all user changes and use an ignored worktree if isolation is needed. + +Resume task [TASK_ID] only after proving its dependency/entry gate. Follow test-first atomic delivery: canonical contracts when the interface changes, failing domain/state tests, PostgreSQL migration/tenant/transaction/outbox tests when durable state changes, implementation through ports, vertical client/adapter coverage when the task involves client behavior, safe telemetry/recovery, traceability evidence, scoped checks, repo:check, repo:build, diff review, and one reversible commit. For documentation-only or other non-durable/non-client tasks, record why those conditional tests do not apply. Do not mark merged code verified without all evidence. + +Git flow is fixed: feat/* or fix/* → PR to dev with hosted checks and no CodeRabbit; merge preserving atomic commits; immediately open dev→main; request exactly one CodeRabbit full review there; reproduce every comment, fix only valid findings, document rejected ones, never request a second review on that PR. Prefer 30–50 commits, hard cap 60, and do not invoke the promotion review over 280 changed files. + +Keep PostgreSQL authoritative, Redis ephemeral, tenant scope explicit, originals/versions immutable, Hybrid default, Local content/path out of cloud, workers without database credentials, Desktop/sidecar allowlisted, Android background payloads content-free, Vietnamese and English complete, and external providers replaceable. Stop and record state for destructive migration risk, unknown overlapping changes, privacy/security fail-open behavior, missing production/signing authority, or a spec conflict. End with the exact handoff record from the runbook. +``` diff --git a/docs/plans/README.md b/docs/plans/README.md index c1e242d6..de83740b 100644 --- a/docs/plans/README.md +++ b/docs/plans/README.md @@ -11,27 +11,37 @@ Each plan must: - preserve deployable independence - state which requirements remain for a later slice -The approved complete implementation sequence and machine-readable traceability manifest are: - -1. 010-engineering-foundation.md -2. 020-identity-audit-entitlements.md -2. 030-artifacts-datasets-evidence.md -2. 040-jobs-processing-approvals.md -2. 050-devices-sync-offline.md -2. 060-collaboration-integrations.md -2. 070-dogfood-folder-spreadsheet.md -2. 100-folder-autopilot.md -2. 110-spreadsheet-auditor.md -2. 120-quote-intelligence.md -2. 130-operations-capture.md -2. 200-invoice-leak-detector.md -2. 210-client-report-factory.md -2. 220-private-data-analyst.md -2. 300-migration-ready.md -2. 310-data-quality-guard.md -2. 320-embedded-importer.md -2. 400-production-readiness.md -2. 500-post-ga-extensions.md -3. requirement-traceability.json ? 611 unique primary assignments (P0 444, P1 154, P2 13). +The planning authorities are: + +1. `000-platform-program.md` — stable program policy and release gates. +2. `001-engineering-foundation.md` — historical foundation planning record. +3. `002-complete-execution-orchestration.md` — implementation DAG, atomic task catalog, cross-plan gates, and edge cases. +4. `003-luna-handoff-runbook.md` — deterministic session resume, Git/PR, CodeRabbit, recovery, and handoff protocol. +5. `execution-orchestration.json` — machine-readable plan/task/dependency ledger and next-task pointer. +6. `requirement-traceability.json` — 611 unique requirement assignments (P0 444, P1 154, P2 13) and their implementation/test/release evidence. + +The dependency-ordered child plans are: + +1. `010-engineering-foundation.md` +2. `020-identity-audit-entitlements.md` +3. `030-artifacts-datasets-evidence.md` +4. `040-jobs-processing-approvals.md` +5. `050-devices-sync-offline.md` +6. `060-collaboration-integrations.md` +7. `070-dogfood-folder-spreadsheet.md` +8. `100-folder-autopilot.md` +9. `110-spreadsheet-auditor.md` +10. `120-quote-intelligence.md` +11. `130-operations-capture.md` +12. `200-invoice-leak-detector.md` +13. `210-client-report-factory.md` +14. `220-private-data-analyst.md` +15. `300-migration-ready.md` +16. `310-data-quality-guard.md` +17. `320-embedded-importer.md` +18. `400-production-readiness.md` +19. `500-post-ga-extensions.md` + +Run `corepack pnpm orchestration:check` before selecting or handing off an implementation task. A child plan owns requirement scope; the orchestration plan owns execution order and task boundaries; the traceability manifest owns evidence status. Git and fetched pull-request state override historical checkpoint hashes. A plan does not change product scope. Any conflict returns to the specification review process. diff --git a/docs/plans/execution-orchestration.json b/docs/plans/execution-orchestration.json new file mode 100644 index 00000000..e154ecb9 --- /dev/null +++ b/docs/plans/execution-orchestration.json @@ -0,0 +1,223 @@ +{ + "version": 1, + "program": "DataBreeze complete platform delivery", + "authority": { + "requirements": "docs/plans/requirement-traceability.json", + "execution": "docs/plans/002-complete-execution-orchestration.md", + "resumeProtocol": "docs/plans/003-luna-handoff-runbook.md" + }, + "requirementTotals": { + "total": 611, + "byPriority": { + "P0": 444, + "P1": 154, + "P2": 13 + } + }, + "checkpoint": { + "observedAt": "2026-08-02T09:06:00Z", + "remoteDev": "86e72d8", + "remoteMain": "8ac8bca", + "lastFeaturePullRequest": 9, + "lastPromotionPullRequest": 8, + "openPullRequestsObserved": 0, + "note": "Historical observation only; every session must fetch and recompute current state." + }, + "reviewPolicy": { + "featurePullRequest": { + "base": "dev", + "codeRabbit": false, + "mergeAfterHostedChecks": true + }, + "promotionPullRequest": { + "base": "main", + "head": "dev", + "codeRabbitInvocations": 1, + "requireFullReview": true, + "maximumFilesBeforeOpening": 280 + }, + "commitBudget": { + "preferredMinimum": 30, + "preferredMaximum": 50, + "hardMaximum": 60 + } + }, + "statusVocabulary": [ + "partial-needs-reconciliation", + "planned", + "in-progress", + "implemented", + "verified", + "released", + "post-ga-planned", + "blocked" + ], + "nextTaskId": "FND-002", + "taskState": { + "FND-001": { + "status": "verified", + "commit": "7c023e5d7f6cfd3a4a9b2c2c0bdf098e0d4bbba5", + "evidence": [ + "docs/operations/foundation-reconciliation-2026-08-02.md", + "tools/repo-cli/test/foundation-reconciliation.test.mjs", + "services/engine/test/launcher.test.mjs", + "services/engine/scripts/run-engine.mjs" + ], + "note": "The task reconciles the foundation against merged dev; OpenTofu remains a hosted validation boundary and no requirement status was promoted." + } + }, + "plans": [ + { + "planId": "010", + "file": "010-engineering-foundation.md", + "requirementCount": 0, + "dependencies": [], + "status": "partial-needs-reconciliation", + "taskIds": ["FND-001", "FND-002", "FND-003", "FND-004", "FND-005", "FND-006", "FND-007"] + }, + { + "planId": "020", + "file": "020-identity-audit-entitlements.md", + "requirementCount": 67, + "dependencies": ["010"], + "status": "partial-needs-reconciliation", + "taskIds": ["IAM-001", "IAM-002", "IAM-003", "IAM-004", "IAM-005", "AUD-001", "AUD-002", "BUA-001", "BUA-002", "IAM-006", "IAM-007"] + }, + { + "planId": "030", + "file": "030-artifacts-datasets-evidence.md", + "requirementCount": 47, + "dependencies": ["020"], + "status": "partial-needs-reconciliation", + "taskIds": ["IAE-001", "IAE-002", "IAE-003", "IAE-004", "IAE-005", "DSM-001", "DSM-002", "DSM-003", "IAE-006", "IAE-007"] + }, + { + "planId": "040", + "file": "040-jobs-processing-approvals.md", + "requirementCount": 30, + "dependencies": ["030"], + "status": "partial-needs-reconciliation", + "taskIds": ["JRA-001", "JRA-002", "JRA-003", "JRA-004", "JRA-005", "JRA-006", "JRA-007", "JRA-008", "JRA-009", "JRA-010", "JRA-011"] + }, + { + "planId": "050", + "file": "050-devices-sync-offline.md", + "requirementCount": 76, + "dependencies": ["040"], + "status": "partial-needs-reconciliation", + "taskIds": ["DSO-001", "DSO-002", "DSO-003", "DSO-004", "DSO-005", "DSO-006", "DSO-007", "DSO-008", "DSO-009", "DSO-010"] + }, + { + "planId": "060", + "file": "060-collaboration-integrations.md", + "requirementCount": 42, + "dependencies": ["050"], + "status": "planned", + "taskIds": ["NCO-001", "NCO-002", "NCO-003", "NCO-004", "INT-001", "INT-002", "INT-003", "INT-004", "NCO-005", "INT-005"] + }, + { + "planId": "070", + "file": "070-dogfood-folder-spreadsheet.md", + "requirementCount": 0, + "dependencies": ["060"], + "status": "planned", + "taskIds": ["DOG-001", "DOG-002", "DOG-003", "DOG-004", "DOG-005", "DOG-006", "DOG-007"] + }, + { + "planId": "100", + "file": "100-folder-autopilot.md", + "requirementCount": 34, + "dependencies": ["070"], + "status": "planned", + "taskIds": ["FA-001", "FA-002", "FA-003", "FA-004", "FA-005", "FA-006", "FA-007"] + }, + { + "planId": "110", + "file": "110-spreadsheet-auditor.md", + "requirementCount": 27, + "dependencies": ["100"], + "status": "planned", + "taskIds": ["SA-001", "SA-002", "SA-003", "SA-004", "SA-005", "SA-006", "SA-007"] + }, + { + "planId": "120", + "file": "120-quote-intelligence.md", + "requirementCount": 27, + "dependencies": ["070"], + "status": "planned", + "taskIds": ["QI-001", "QI-002", "QI-003", "QI-004", "QI-005", "QI-006", "QI-007"] + }, + { + "planId": "130", + "file": "130-operations-capture.md", + "requirementCount": 40, + "dependencies": ["070"], + "status": "planned", + "taskIds": ["OC-001", "OC-002", "OC-003", "OC-004", "OC-005", "OC-006", "OC-007", "OC-008"] + }, + { + "planId": "200", + "file": "200-invoice-leak-detector.md", + "requirementCount": 27, + "dependencies": ["120"], + "status": "planned", + "taskIds": ["ILD-001", "ILD-002", "ILD-003", "ILD-004", "ILD-005", "ILD-006", "ILD-007"] + }, + { + "planId": "210", + "file": "210-client-report-factory.md", + "requirementCount": 27, + "dependencies": ["110", "120"], + "status": "planned", + "taskIds": ["CRF-001", "CRF-002", "CRF-003", "CRF-004", "CRF-005", "CRF-006", "CRF-007"] + }, + { + "planId": "220", + "file": "220-private-data-analyst.md", + "requirementCount": 37, + "dependencies": ["130", "210"], + "status": "planned", + "taskIds": ["PDA-001", "PDA-002", "PDA-003", "PDA-004", "PDA-005", "PDA-006", "PDA-007", "PDA-008"] + }, + { + "planId": "300", + "file": "300-migration-ready.md", + "requirementCount": 32, + "dependencies": ["220"], + "status": "planned", + "taskIds": ["MR-001", "MR-002", "MR-003", "MR-004", "MR-005", "MR-006", "MR-007"] + }, + { + "planId": "310", + "file": "310-data-quality-guard.md", + "requirementCount": 35, + "dependencies": ["200", "300"], + "status": "planned", + "taskIds": ["DQG-001", "DQG-002", "DQG-003", "DQG-004", "DQG-005", "DQG-006", "DQG-007", "DQG-008"] + }, + { + "planId": "320", + "file": "320-embedded-importer.md", + "requirementCount": 27, + "dependencies": ["050", "060"], + "status": "planned", + "taskIds": ["EI-001", "EI-002", "EI-003", "EI-004", "EI-005", "EI-006", "EI-007"] + }, + { + "planId": "400", + "file": "400-production-readiness.md", + "requirementCount": 23, + "dependencies": ["300", "310", "320"], + "status": "planned", + "taskIds": ["GA-001", "GA-002", "GA-003", "GA-004", "GA-005", "GA-006", "GA-007", "GA-008", "GA-009", "GA-010", "GA-011", "GA-012"] + }, + { + "planId": "500", + "file": "500-post-ga-extensions.md", + "requirementCount": 13, + "dependencies": ["400"], + "status": "post-ga-planned", + "taskIds": ["P2-001", "P2-002", "P2-003", "P2-004"] + } + ] +} diff --git a/package.json b/package.json index 78a78b15..b46e0aba 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,10 @@ "lint": "eslint . && node tools/repo-cli/src/check-dependency-boundaries.mjs", "local:smoke": "node tools/repo-cli/src/local-services-smoke.mjs", "infra:check": "node tools/repo-cli/src/check-aws-infrastructure.mjs", + "orchestration:check": "node tools/repo-cli/src/check-execution-orchestration.mjs", "repo:bootstrap": "corepack pnpm install --frozen-lockfile", "repo:build": "corepack pnpm build", - "repo:check": "corepack pnpm format:check && corepack pnpm lint && corepack pnpm typecheck && corepack pnpm requirements:check && corepack pnpm contracts:check && corepack pnpm test", + "repo:check": "corepack pnpm format:check && corepack pnpm lint && corepack pnpm typecheck && corepack pnpm orchestration:check && corepack pnpm requirements:check && corepack pnpm contracts:check && corepack pnpm test", "repo:dev": "turbo run dev --parallel", "repo:test": "corepack pnpm test", "requirements:check": "node tools/repo-cli/src/generate-requirement-index.mjs --check", diff --git a/services/engine/scripts/run-engine.mjs b/services/engine/scripts/run-engine.mjs index 30c73029..ae26eec8 100644 --- a/services/engine/scripts/run-engine.mjs +++ b/services/engine/scripts/run-engine.mjs @@ -54,7 +54,7 @@ if (version.error || version.status !== 0) { format: [...run, 'ruff', 'format', '--check', '.'], lint: [...run, 'ruff', 'check', '.'], 'python-version': [...run, 'python', '--version'], - test: [...run, 'pytest'], + test: [...run, 'python', '-m', 'pytest'], typecheck: [...run, 'mypy'], }; if (operation === 'build') { diff --git a/services/engine/test/launcher.test.mjs b/services/engine/test/launcher.test.mjs index 3ede875a..3f53bbdd 100644 --- a/services/engine/test/launcher.test.mjs +++ b/services/engine/test/launcher.test.mjs @@ -1,5 +1,6 @@ import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import path from 'node:path'; import test from 'node:test'; @@ -51,6 +52,11 @@ test('uv exact-version parsing rejects prefix collisions and undocumented suffix assert.equal(isRequiredUvVersion(`uv 0.11.32 (${`x`.repeat(161)})`), false); }); +test('launcher invokes pytest through the Python module runner', () => { + const source = readFileSync(launcher, 'utf8'); + assert.match(source, /test: \[\.\.\.run, 'python', '-m', 'pytest'\]/u); +}); + test( 'launcher rejects a prefix-collision version from a fake executable', { diff --git a/tools/repo-cli/src/check-execution-orchestration.mjs b/tools/repo-cli/src/check-execution-orchestration.mjs new file mode 100644 index 00000000..15688116 --- /dev/null +++ b/tools/repo-cli/src/check-execution-orchestration.mjs @@ -0,0 +1,314 @@ +import { existsSync, readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; + +const expectedPlans = new Map([ + ['010', ['010-engineering-foundation.md', 0]], + ['020', ['020-identity-audit-entitlements.md', 67]], + ['030', ['030-artifacts-datasets-evidence.md', 47]], + ['040', ['040-jobs-processing-approvals.md', 30]], + ['050', ['050-devices-sync-offline.md', 76]], + ['060', ['060-collaboration-integrations.md', 42]], + ['070', ['070-dogfood-folder-spreadsheet.md', 0]], + ['100', ['100-folder-autopilot.md', 34]], + ['110', ['110-spreadsheet-auditor.md', 27]], + ['120', ['120-quote-intelligence.md', 27]], + ['130', ['130-operations-capture.md', 40]], + ['200', ['200-invoice-leak-detector.md', 27]], + ['210', ['210-client-report-factory.md', 27]], + ['220', ['220-private-data-analyst.md', 37]], + ['300', ['300-migration-ready.md', 32]], + ['310', ['310-data-quality-guard.md', 35]], + ['320', ['320-embedded-importer.md', 27]], + ['400', ['400-production-readiness.md', 23]], + ['500', ['500-post-ga-extensions.md', 13]], +]); +const expectedPriorityTotals = { P0: 444, P1: 154, P2: 13 }; +const expectedReviewPolicy = { + commitBudget: { hardMaximum: 60, preferredMaximum: 50, preferredMinimum: 30 }, + featurePullRequest: { base: 'dev', codeRabbit: false, mergeAfterHostedChecks: true }, + promotionPullRequest: { + base: 'main', + codeRabbitInvocations: 1, + head: 'dev', + maximumFilesBeforeOpening: 280, + requireFullReview: true, + }, +}; +const requiredRunbookHeadings = [ + '## Start-of-session algorithm', + '## Resume-state decision table', + '## Atomic task execution loop', + '## Pull-request and CodeRabbit protocol', + '## Edge-case response matrix', + '## End-of-session handoff record', + '## Luna bootstrap prompt', +]; +const traceStatuses = new Set(['planned', 'partial', 'implemented', 'verified', 'released']); + +function parseOptions(argumentsList) { + let root = path.resolve(import.meta.dirname, '..', '..', '..'); + for (let index = 0; index < argumentsList.length; index += 1) { + const argument = argumentsList[index]; + if (argument !== '--root') throw new Error(`Unknown option: ${argument}`); + const value = argumentsList[index + 1]; + if (value === undefined) throw new Error('The --root option requires a value.'); + root = path.resolve(value); + index += 1; + } + return { root }; +} + +function readJson(filePath) { + return JSON.parse(readFileSync(filePath, 'utf8')); +} + +function stableJson(value) { + if (Array.isArray(value)) return value.map(stableJson); + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, entry]) => [key, stableJson(entry)]), + ); + } + return value; +} + +function sameJson(left, right) { + return JSON.stringify(stableJson(left)) === JSON.stringify(stableJson(right)); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); +} + +function pathExists(repositoryRoot, declaredPath) { + if (typeof declaredPath !== 'string' || declaredPath.trim() === '') return false; + if (/[{}*?]/u.test(declaredPath)) return false; + if (declaredPath.includes('\\')) return false; + const segments = declaredPath.split('/'); + if (segments.some((segment) => segment === '.' || segment === '..')) return false; + const candidate = path.resolve(repositoryRoot, ...segments); + const relative = path.relative(repositoryRoot, candidate); + if (relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) return false; + return existsSync(candidate); +} + +function validateDag(plans, diagnostics) { + const byId = new Map(plans.map((plan) => [plan.planId, plan])); + const active = new Set(); + const complete = new Set(); + + function visit(planId) { + if (complete.has(planId)) return; + if (active.has(planId)) { + diagnostics.push(`execution dependency cycle includes ${planId}`); + return; + } + active.add(planId); + for (const dependency of byId.get(planId)?.dependencies ?? []) { + if (!byId.has(dependency)) { + diagnostics.push(`plan ${planId} has unknown dependency ${dependency}`); + } else { + visit(dependency); + } + } + active.delete(planId); + complete.add(planId); + } + + for (const planId of byId.keys()) visit(planId); +} + +function run(argumentsList) { + const { root } = parseOptions(argumentsList); + const plansDirectory = path.join(root, 'docs', 'plans'); + const ledgerPath = path.join(plansDirectory, 'execution-orchestration.json'); + const traceabilityPath = path.join(plansDirectory, 'requirement-traceability.json'); + const orchestrationPath = path.join(plansDirectory, '002-complete-execution-orchestration.md'); + const runbookPath = path.join(plansDirectory, '003-luna-handoff-runbook.md'); + const requiredFiles = [ledgerPath, traceabilityPath, orchestrationPath, runbookPath]; + const missingFiles = requiredFiles.filter((filePath) => !existsSync(filePath)); + if (missingFiles.length > 0) { + throw new Error(`Missing orchestration files:\n${missingFiles.join('\n')}`); + } + + const ledger = readJson(ledgerPath); + const traceability = readJson(traceabilityPath); + const orchestration = readFileSync(orchestrationPath, 'utf8'); + const runbook = readFileSync(runbookPath, 'utf8'); + const diagnostics = []; + + if (ledger.version !== 1) diagnostics.push(`unsupported ledger version ${ledger.version}`); + if (!sameJson(ledger.reviewPolicy, expectedReviewPolicy)) { + diagnostics.push('reviewPolicy does not preserve the approved dev/main/CodeRabbit flow'); + } + if (ledger.requirementTotals?.total !== 611) { + diagnostics.push( + `ledger requirement total is ${ledger.requirementTotals?.total}; expected 611`, + ); + } + if (!sameJson(ledger.requirementTotals?.byPriority, expectedPriorityTotals)) { + diagnostics.push('ledger priority totals differ from P0=444, P1=154, P2=13'); + } + + const plans = Array.isArray(ledger.plans) ? ledger.plans : []; + const actualPlanIds = plans.map((plan) => plan.planId); + if (!sameJson(actualPlanIds, [...expectedPlans.keys()])) { + diagnostics.push('plan IDs or ordering differ from the approved 19-plan sequence'); + } + + const requirements = Array.isArray(traceability.requirements) ? traceability.requirements : []; + const requirementIds = new Set(); + const priorityCounts = { P0: 0, P1: 0, P2: 0 }; + const primaryPlanCounts = new Map(); + for (const requirement of requirements) { + if (requirementIds.has(requirement.requirementId)) { + diagnostics.push(`duplicate requirement ${requirement.requirementId}`); + } + requirementIds.add(requirement.requirementId); + if (!(requirement.priority in priorityCounts)) { + diagnostics.push( + `requirement ${requirement.requirementId} has invalid priority ${requirement.priority}`, + ); + } else { + priorityCounts[requirement.priority] += 1; + } + primaryPlanCounts.set( + requirement.primaryPlan, + (primaryPlanCounts.get(requirement.primaryPlan) ?? 0) + 1, + ); + if (!traceStatuses.has(requirement.status)) { + diagnostics.push( + `requirement ${requirement.requirementId} has invalid status ${requirement.status}`, + ); + } + if (['verified', 'released'].includes(requirement.status)) { + const testPaths = Array.isArray(requirement.testPaths) ? requirement.testPaths : []; + const evidencePaths = Array.isArray(requirement.releaseEvidence) + ? requirement.releaseEvidence + : []; + if (testPaths.length === 0 || !testPaths.every((entry) => pathExists(root, entry))) { + diagnostics.push( + `verified requirement ${requirement.requirementId} lacks exact existing test paths`, + ); + } + if (evidencePaths.length === 0 || !evidencePaths.every((entry) => pathExists(root, entry))) { + diagnostics.push( + `verified requirement ${requirement.requirementId} lacks exact existing release-evidence paths`, + ); + } + } + } + if (requirements.length !== 611) + diagnostics.push(`traceability has ${requirements.length} requirements`); + if (!sameJson(priorityCounts, expectedPriorityTotals)) { + diagnostics.push(`traceability priority totals are ${JSON.stringify(priorityCounts)}`); + } + + const planIds = new Set(); + const planFiles = new Set(); + const taskIds = new Set(); + for (const plan of plans) { + if (planIds.has(plan.planId)) diagnostics.push(`duplicate plan ${plan.planId}`); + planIds.add(plan.planId); + if (planFiles.has(plan.file)) diagnostics.push(`duplicate plan file ${plan.file}`); + planFiles.add(plan.file); + + const expected = expectedPlans.get(plan.planId); + if (expected === undefined) continue; + const [expectedFile, expectedRequirementCount] = expected; + if (plan.file !== expectedFile) { + diagnostics.push(`plan ${plan.planId} file is ${plan.file}; expected ${expectedFile}`); + } + if (plan.requirementCount !== expectedRequirementCount) { + diagnostics.push( + `plan ${plan.planId} owns ${plan.requirementCount}; expected ${expectedRequirementCount}`, + ); + } + if ((primaryPlanCounts.get(plan.file) ?? 0) !== expectedRequirementCount) { + diagnostics.push( + `traceability assigns ${primaryPlanCounts.get(plan.file) ?? 0} requirements to ${plan.file}; expected ${expectedRequirementCount}`, + ); + } + const childPlanPath = path.join(plansDirectory, plan.file); + if (!existsSync(childPlanPath) || statSync(childPlanPath).size === 0) { + diagnostics.push(`plan ${plan.planId} child file is missing or empty: ${plan.file}`); + } + if (!ledger.statusVocabulary?.includes(plan.status)) { + diagnostics.push(`plan ${plan.planId} has unsupported status ${plan.status}`); + } + if (!Array.isArray(plan.taskIds) || plan.taskIds.length === 0) { + diagnostics.push(`plan ${plan.planId} has no task inventory`); + continue; + } + for (const taskId of plan.taskIds) { + if (taskIds.has(taskId)) diagnostics.push(`duplicate orchestration task ${taskId}`); + taskIds.add(taskId); + const heading = new RegExp(`^#### ${escapeRegExp(taskId)} —`, 'mu'); + if (!heading.test(orchestration)) { + diagnostics.push(`orchestration heading is missing for task ${taskId}`); + } + } + } + + validateDag(plans, diagnostics); + if (!taskIds.has(ledger.nextTaskId)) { + diagnostics.push(`nextTaskId ${ledger.nextTaskId} is not in the task inventory`); + } + const taskState = ledger.taskState ?? {}; + if (taskState === null || typeof taskState !== 'object' || Array.isArray(taskState)) { + diagnostics.push('taskState must be an object'); + } else { + for (const [taskId, state] of Object.entries(taskState)) { + if (!taskIds.has(taskId)) { + diagnostics.push(`taskState contains unknown task ${taskId}`); + continue; + } + if (state === null || typeof state !== 'object' || Array.isArray(state)) { + diagnostics.push(`taskState for ${taskId} must be an object`); + continue; + } + if (!ledger.statusVocabulary?.includes(state.status)) { + diagnostics.push(`task ${taskId} has unsupported status ${state.status}`); + } + if (['verified', 'released'].includes(state.status)) { + if (!/^[0-9a-f]{40}$/u.test(state.commit ?? '')) { + diagnostics.push(`verified task ${taskId} must name a full commit SHA`); + } + if (!Array.isArray(state.evidence) || state.evidence.length === 0) { + diagnostics.push(`verified task ${taskId} must name evidence paths`); + } else if (!state.evidence.every((entry) => pathExists(root, entry))) { + diagnostics.push(`verified task ${taskId} has missing evidence paths`); + } + } + } + } + for (const heading of requiredRunbookHeadings) { + if (!runbook.split(/\r?\n/u).includes(heading)) + diagnostics.push(`runbook heading missing: ${heading}`); + } + + if (diagnostics.length > 0) { + process.stderr.write(`${diagnostics.sort().join('\n')}\n`); + return 1; + } + + process.stdout.write( + `${JSON.stringify({ + nextTaskId: ledger.nextTaskId, + planCount: plans.length, + requirementCount: requirements.length, + taskCount: taskIds.size, + })}\n`, + ); + return 0; +} + +try { + process.exitCode = run(process.argv.slice(2)); +} catch (error) { + process.stderr.write(`${error.message}\n`); + process.exitCode = 1; +} diff --git a/tools/repo-cli/test/execution-orchestration.test.mjs b/tools/repo-cli/test/execution-orchestration.test.mjs new file mode 100644 index 00000000..9eb2f267 --- /dev/null +++ b/tools/repo-cli/test/execution-orchestration.test.mjs @@ -0,0 +1,243 @@ +import assert from 'node:assert/strict'; +import { cpSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..'); +const checkerPath = path.join( + repositoryRoot, + 'tools', + 'repo-cli', + 'src', + 'check-execution-orchestration.mjs', +); + +const expectedPlans = new Map([ + ['010', ['010-engineering-foundation.md', 0]], + ['020', ['020-identity-audit-entitlements.md', 67]], + ['030', ['030-artifacts-datasets-evidence.md', 47]], + ['040', ['040-jobs-processing-approvals.md', 30]], + ['050', ['050-devices-sync-offline.md', 76]], + ['060', ['060-collaboration-integrations.md', 42]], + ['070', ['070-dogfood-folder-spreadsheet.md', 0]], + ['100', ['100-folder-autopilot.md', 34]], + ['110', ['110-spreadsheet-auditor.md', 27]], + ['120', ['120-quote-intelligence.md', 27]], + ['130', ['130-operations-capture.md', 40]], + ['200', ['200-invoice-leak-detector.md', 27]], + ['210', ['210-client-report-factory.md', 27]], + ['220', ['220-private-data-analyst.md', 37]], + ['300', ['300-migration-ready.md', 32]], + ['310', ['310-data-quality-guard.md', 35]], + ['320', ['320-embedded-importer.md', 27]], + ['400', ['400-production-readiness.md', 23]], + ['500', ['500-post-ga-extensions.md', 13]], +]); + +function readJson(relativePath) { + return JSON.parse(readFileSync(path.join(repositoryRoot, relativePath), 'utf8')); +} + +function assertAcyclic(plans) { + const byId = new Map(plans.map((plan) => [plan.planId, plan])); + const active = new Set(); + const complete = new Set(); + + function visit(planId) { + if (complete.has(planId)) return; + assert.ok(!active.has(planId), `dependency cycle at ${planId}`); + active.add(planId); + for (const dependency of byId.get(planId).dependencies) visit(dependency); + active.delete(planId); + complete.add(planId); + } + + for (const planId of byId.keys()) visit(planId); +} + +function withTemporaryPlans(mutate, assertion) { + const temporaryRoot = mkdtempSync(path.join(tmpdir(), 'databreeze-orchestration-')); + try { + cpSync(path.join(repositoryRoot, 'docs', 'plans'), path.join(temporaryRoot, 'docs', 'plans'), { + recursive: true, + }); + const ledgerPath = path.join(temporaryRoot, 'docs', 'plans', 'execution-orchestration.json'); + const traceabilityPath = path.join( + temporaryRoot, + 'docs', + 'plans', + 'requirement-traceability.json', + ); + const state = { + ledger: JSON.parse(readFileSync(ledgerPath, 'utf8')), + traceability: JSON.parse(readFileSync(traceabilityPath, 'utf8')), + }; + mutate(state); + writeFileSync(ledgerPath, `${JSON.stringify(state.ledger, null, 2)}\n`); + writeFileSync(traceabilityPath, `${JSON.stringify(state.traceability, null, 2)}\n`); + const result = spawnSync(process.execPath, [checkerPath, '--root', temporaryRoot], { + encoding: 'utf8', + }); + assertion(result); + } finally { + rmSync(temporaryRoot, { force: true, recursive: true }); + } +} + +test('execution ledger covers the complete dependency-ordered implementation program', () => { + const ledger = readJson('docs/plans/execution-orchestration.json'); + const traceability = readJson('docs/plans/requirement-traceability.json'); + const orchestration = readFileSync( + path.join(repositoryRoot, 'docs', 'plans', '002-complete-execution-orchestration.md'), + 'utf8', + ); + + assert.equal(ledger.version, 1); + assert.deepEqual( + ledger.plans.map((plan) => plan.planId), + [...expectedPlans.keys()], + ); + assert.equal(ledger.requirementTotals.total, 611); + assert.deepEqual(ledger.requirementTotals.byPriority, { P0: 444, P1: 154, P2: 13 }); + + const traceCounts = traceability.requirements.reduce((counts, requirement) => { + counts[requirement.primaryPlan] = (counts[requirement.primaryPlan] ?? 0) + 1; + return counts; + }, {}); + const taskIds = new Set(); + for (const plan of ledger.plans) { + const [file, expectedRequirementCount] = expectedPlans.get(plan.planId); + assert.equal(plan.file, file); + assert.equal(plan.requirementCount, expectedRequirementCount); + assert.equal(traceCounts[file] ?? 0, expectedRequirementCount); + assert.ok(existsSync(path.join(repositoryRoot, 'docs', 'plans', file))); + assert.ok(plan.taskIds.length > 0, `${plan.planId} task inventory`); + for (const dependency of plan.dependencies) assert.ok(expectedPlans.has(dependency)); + for (const taskId of plan.taskIds) { + assert.ok(!taskIds.has(taskId), `duplicate orchestration task ${taskId}`); + taskIds.add(taskId); + assert.match(orchestration, new RegExp(`^#### ${taskId} —`, 'm')); + } + } + assertAcyclic(ledger.plans); + assert.ok(taskIds.has(ledger.nextTaskId)); +}); + +test('handoff policy preserves the requested dev and main review flow', () => { + const ledger = readJson('docs/plans/execution-orchestration.json'); + assert.deepEqual(ledger.reviewPolicy.featurePullRequest, { + base: 'dev', + codeRabbit: false, + mergeAfterHostedChecks: true, + }); + assert.deepEqual(ledger.reviewPolicy.promotionPullRequest, { + base: 'main', + head: 'dev', + codeRabbitInvocations: 1, + requireFullReview: true, + maximumFilesBeforeOpening: 280, + }); + assert.deepEqual(ledger.reviewPolicy.commitBudget, { + preferredMinimum: 30, + preferredMaximum: 50, + hardMaximum: 60, + }); +}); + +test('the handoff runbook contains deterministic resume and failure protocols', () => { + const runbook = readFileSync( + path.join(repositoryRoot, 'docs', 'plans', '003-luna-handoff-runbook.md'), + 'utf8', + ); + for (const heading of [ + '## Start-of-session algorithm', + '## Resume-state decision table', + '## Atomic task execution loop', + '## Pull-request and CodeRabbit protocol', + '## Edge-case response matrix', + '## End-of-session handoff record', + '## Luna bootstrap prompt', + ]) { + assert.match(runbook, new RegExp(`^${heading}$`, 'm')); + } +}); + +test('repository checker validates the committed orchestration package', () => { + const result = spawnSync(process.execPath, [checkerPath, '--root', repositoryRoot], { + encoding: 'utf8', + }); + assert.equal(result.status, 0, result.stderr); + assert.match(result.stdout, /"planCount":19/u); + assert.match(result.stdout, /"requirementCount":611/u); +}); + +test('ledger records verified task evidence before advancing the next task', () => { + const ledger = readJson('docs/plans/execution-orchestration.json'); + assert.equal(ledger.nextTaskId, 'FND-002'); + assert.deepEqual(ledger.taskState?.['FND-001']?.status, 'verified'); + assert.match(ledger.taskState?.['FND-001']?.commit ?? '', /^[0-9a-f]{40}$/u); + assert.ok( + ledger.taskState['FND-001'].evidence.includes( + 'docs/operations/foundation-reconciliation-2026-08-02.md', + ), + ); +}); + +test('CodeRabbit promotion disposition records one review and rejected claims', () => { + const disposition = readFileSync( + path.join(repositoryRoot, 'docs', 'operations', 'code-review-11-disposition.md'), + 'utf8', + ); + assert.match(disposition, /Promotion PR.*#11/u); + assert.match(disposition, /one permitted full CodeRabbit review/u); + assert.match(disposition, /Duplicate plan catalog/u); + assert.match(disposition, /Docstring coverage warning/u); +}); + +test('repository checker rejects dependency cycles', () => { + withTemporaryPlans( + ({ ledger }) => { + ledger.plans[0].dependencies = ['500']; + }, + (result) => { + assert.notEqual(result.status, 0); + assert.match(result.stderr, /execution dependency cycle/u); + }, + ); +}); + +test('repository checker rejects false verified requirement evidence', () => { + withTemporaryPlans( + ({ traceability }) => { + traceability.requirements[0].status = 'verified'; + traceability.requirements[0].testPaths = ['missing/tests']; + traceability.requirements[0].releaseEvidence = ['missing/evidence.json']; + }, + (result) => { + assert.notEqual(result.status, 0); + assert.match(result.stderr, /lacks exact existing test paths/u); + assert.match(result.stderr, /lacks exact existing release-evidence paths/u); + }, + ); +}); + +test('repository checker rejects task evidence paths that escape the repository root', () => { + withTemporaryPlans( + ({ ledger }) => { + ledger.taskState = { + 'FND-001': { + status: 'verified', + commit: '0'.repeat(40), + evidence: ['..'], + }, + }; + }, + (result) => { + assert.notEqual(result.status, 0); + assert.match(result.stderr, /verified task FND-001 has missing evidence paths/u); + }, + ); +}); diff --git a/tools/repo-cli/test/foundation-reconciliation.test.mjs b/tools/repo-cli/test/foundation-reconciliation.test.mjs new file mode 100644 index 00000000..20898e70 --- /dev/null +++ b/tools/repo-cli/test/foundation-reconciliation.test.mjs @@ -0,0 +1,39 @@ +import assert from 'node:assert/strict'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import test from 'node:test'; + +const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..'); +const evidencePath = path.join( + repositoryRoot, + 'docs', + 'operations', + 'foundation-reconciliation-2026-08-02.md', +); + +test('foundation reconciliation records every approved foundation task and gate', () => { + assert.ok(existsSync(evidencePath), 'reconciliation evidence file is missing'); + const evidence = readFileSync(evidencePath, 'utf8'); + + assert.match(evidence, /^# Engineering Foundation Reconciliation$/mu); + assert.match( + evidence, + /\*\*Source commit:\*\* `86e72d8569057d2a14ed6bb1672ce6a573fa8d7c` \(display prefix: `86e72d8`\)/u, + ); + assert.match(evidence, /\*\*Requirement status:\*\* no requirement promoted to `verified`/u); + for (let taskNumber = 1; taskNumber <= 23; taskNumber += 1) { + assert.match(evidence, new RegExp(`\\| Task ${taskNumber} \\|`, 'u')); + } + for (const requiredSection of [ + '## Reconciliation method', + '## Task outcomes', + '## Fresh verification evidence', + '## Known environment limits', + '## Release and rollback decision', + ]) { + assert.match(evidence, new RegExp(`^${requiredSection}$`, 'mu')); + } + assert.match(evidence, /No AWS infrastructure was applied/u); + assert.match(evidence, /No customer data or credentials were used/u); +});