Skip to content

feat(portal): SPEC-014 v0.8 provider portal (Phases 1A+1B+1C, 3-round audit gate)#110

Merged
Augustas11 merged 6 commits into
mainfrom
feat/spec-014-provider-portal
Jun 21, 2026
Merged

feat(portal): SPEC-014 v0.8 provider portal (Phases 1A+1B+1C, 3-round audit gate)#110
Augustas11 merged 6 commits into
mainfrom
feat/spec-014-provider-portal

Conversation

@Augustas11

Copy link
Copy Markdown
Owner

Summary

  • Lands SPEC-014 v0.8 Provider Portal as a single-file web bundle at frontdoor/provider-portal/index.html — AUTH-3 fail-CLOSED loader, AUTH-1 sign-in (in-memory only), AUTH-2 401/403/404 identical copy + stale-config guard, same-origin proxy fail-loud, all five surfaces (Machine, Setup & Updates, Earn, Monitoring placeholder, Identity).
  • Adds check-bundle.sh build-time grep guard for AC 8(b) (privileged-key route + identifier isolation) + AC 8(f) (single-machine copy hygiene). Self-protected via Bash string concatenation so external scans with the same patterns produce zero matches on the script itself.
  • Phases 1A / 1B / 1C each went through their own codex IMPL audit gate (0 CRITICAL / 0 HIGH / 0 MEDIUM round-2 LOCK before the next phase began); single PR per the BUILD prompts' unified-branch plan.

What ships

Surface Source Notes
A — Machine /v1/pool/check (same-origin) + /providers/{id}/earnings (same-origin) A.1 header + A.2 counters + A.3 needs-attention. A.4 deferred (Open Q5/Q10).
B — Setup & Updates SPEC-003 §5 FR-D1 + FR-D2 + §4 FR-C2 + SPEC-013 §6 + GitHub Releases API B.1 grid + B.1a sizing + B.2 steps + B.3 feed (5-min cache, rate-limit + CORS fail-loud, plain-text body). No autotune banner per SPEC-013 NFR-4.
C — Earn /providers/{id}/earnings (reuses Phase 1A cache) C.1 credit totals + C.2 fiat-not-specified card (no Stripe / no bank-link / no payout-now). C.3/C.4 deferred (Open Q4).
D — Monitoring none Single placeholder card. Zero network requests issued by the surface mount.
E — Identity state.pool.data lazy read Read-only: provider_id / tier / state / coordinator base URL. No rotation, no removal, no notification toggles.

Privacy / security invariants enforced

  • No localStorage / sessionStorage / document.cookie / indexedDB — session is in-memory only; page reload returns to sign-in.
  • No remote command execution — every CTA is copy-to-clipboard; no POST/PUT/DELETE; no XHR; no WebSocket; no sendBeacon.
  • No privileged-key routes referenced anywhere; no operator_key ever prompted, parsed, or transmitted.
  • 403 and 404 render IDENTICAL "sign-in rejected" copy (SPEC-005 §11.5).
  • After two consecutive 401/403/404 on the same surface, sign-in screen adds a stale-config notice ALONGSIDE the identical rejection copy.
  • require_provider_tokens strict-true only; any other value (false, "true", 1, null) renders the SPEC-002 FR-P12 + SPEC-005 §11.5 explanation and makes zero further network calls.
  • Release body rendered via document.createTextNode only — no innerHTML of remote data.
  • Bundle never reads Access-Control-Allow-Origin as application data.

Commit history on this branch

2c9e2dc feat(portal): SPEC-014 Phase 1C implementation + IMPL audit LOCK
0616b98 feat(portal): SPEC-014 Phase 1B implementation + IMPL audit LOCK
826b3cc audit(portal): SPEC-014 Phase 1A round 2 LOCK — both HIGH CLOSED, 0 new
5195418 spec(portal): unify SPEC-014 IMPL phases onto single branch + PR
3cd7787 feat(portal): SPEC-014 Phase 1A implementation (pre-fix; 2 HIGH open)
970d63e spec(portal): SPEC-014 v0.8 provider portal + 3 IMPL build prompts

Audit-loop findings closed across the three phases:

  • Phase 1A round 1 → 2 HIGH (A.2 non-true flag-false unreachable; C.4 stale-config notice unreachable through retry flow). Round 2 LOCK.
  • Phase 1B round 1 → 2 MEDIUM (C.4 unsupported SPEC-003 §6.2 cite on autotune step; H.1 raw hex literals in new CSS). Round 2 LOCK.
  • Phase 1C round 1 → 1 MEDIUM (E.5 check-bundle.sh self-matched the operator-key regex from its own comments + echo messages). Round 2 LOCK.

Test plan

  • CI green (no required reviewers per project memory — gating on whatever workflows exist).
  • frontdoor/provider-portal/check-bundle.sh exits 0 on main after merge.
  • Operator follow-up PR adds .github/workflows/ step running check-bundle.sh on any PR touching frontdoor/provider-portal/** (SPEC-014 §8(b) + §8(f) CI gate).
  • Operator runbook (SPEC-014 §10.4): deploy portal-config.json + reverse proxy + verify before pointing DNS.

v0.2 reopens after Open Qs (Q2 / Q3 / Q4 / Q5 / Q6 / Q7 / Q8 / Q9 / Q10 / Q11) land their owning-spec amendments.

🤖 Generated with Claude Code

Augustas11 and others added 6 commits June 21, 2026 15:02
Lands the seller-facing Provider Portal spec, its audit artifact,
the spec-build/spec-audit prompts that produced it, and the three
IMPL build prompts that drive the implementation:

- SPEC-014-provider-portal.md v0.8 (8 audit rounds: 3 HIGH + 2
  MEDIUM applied, remaining MEDIUM/MINORs accepted as v0.2 backlog
  per operator instruction)
- SPEC-014-audit.md (latest codex audit output)
- BUILD_SPEC_014_PROMPT.md / AUDIT_SPEC_014_PROMPT.md (the spec-
  writing + spec-audit prompts; v0.12 / round 11)
- BUILD_SPEC_014_IMPL_PHASE_1A/1B/1C_PROMPT.md (new) — one IMPL
  build prompt per §11 phase: 1A scaffolding + AUTH-3 + sign-in +
  Surface A; 1B Surface B (Setup & Updates + GitHub Releases feed
  with CORS/rate-limit fail-loud); 1C Surfaces C/D/E + sidebar
  polish + check-bundle.sh AC 8(b)+8(f) grep guard.

Each IMPL prompt is self-contained (constraints, required reading,
exact edits, done criteria, out-of-scope, self-check command) per
the project's BUILD_SPEC_NNN_IMPL_PHASE_* convention. Phases land
sequentially: each goes through its own IMPL audit gate
(specs/AUDIT_SPEC_014_IMPL_PHASE_*_PROMPT.md, drafted later) and
ships as its own PR per memory: feedback-build-audit-loop.

No implementation code lands in this commit — the scaffold at
frontdoor/provider-portal/ remains .gitkeep + one-line README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1A of SPEC-014 v0.8 per BUILD_SPEC_014_IMPL_PHASE_1A_PROMPT.md:
single-file bundle with AUTH-3 fail-CLOSED loader, AUTH-1 sign-in
(in-memory only), AUTH-2 401/403/404 handling + stale-config guard,
Surface A (header + counters + needs-attention), sidebar shell with
B/C/D/E stubbed, same-origin proxy fail-loud banner, mobile collapse,
SPEC-009 §6 visual tokens verbatim.

Files:
- frontdoor/provider-portal/index.html (NEW, ~38 KB single-file
  bundle, inline JS+CSS, no build step, no CDN)
- frontdoor/provider-portal/portal-config.json.example (NEW)
- frontdoor/provider-portal/README.md (extended from one-line
  scaffold to operator setup + reverse-proxy contract)
- specs/AUDIT_SPEC_014_IMPL_PHASE_1A_PROMPT.md (NEW; the IMPL
  audit prompt fired against this commit)
- specs/SPEC-014-impl-audit.md (NEW; codex round 1 audit output:
  0 CRITICAL / 2 HIGH / 0 MEDIUM / 0 MINOR / 1 QUESTION)

Status: NOT audit-clean — 2 HIGH findings open per the round 1
audit (require_provider_tokens=false page unreachable; stale-config
second-failure notice unreachable through actual sign-in flow).
Per memory: feedback-build-audit-loop, fix rounds + re-audit
continue on this branch before PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Revises the three IMPL build prompts so Phases 1A/1B/1C all land
on `feat/spec-014-provider-portal` and ship as ONE PR (not three).
Audit gates between phases still bind — but they stop forward
progress *within* the branch (commit fixes until 0 CRITICAL/HIGH/
MEDIUM, then move to the next phase), not as separate PRs.

Changes:
- BUILD_SPEC_014_IMPL_PHASE_1A_PROMPT.md: branch is
  `feat/spec-014-provider-portal` (was `feat/spec-014-portal-
  phase-1a`); operator notes spell out the single-PR flow.
- BUILD_SPEC_014_IMPL_PHASE_1B_PROMPT.md: prerequisite reworded
  from "Phase 1A merged to main" to "Phase 1A LOCKED on the same
  branch"; explicit "do NOT branch or push" instruction.
- BUILD_SPEC_014_IMPL_PHASE_1C_PROMPT.md: same as 1B; operator
  notes describe opening the single PR after Phase 1C LOCKs.

Rationale: SPEC-014 v0.1 is a single read-side web surface; the
phased structure is for audit discipline, not for separable
shipping units. The original three-PR plan would have forced
three review cycles for one cohesive surface.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Round 2 codex audit verifies closure of the round-1 HIGH findings:

- A.2 (require_provider_tokens non-true unreachable flag-false
  page): CLOSED. validateConfig() now treats any non-true value
  (false, "true", 1, null) as flag-false and routes it past the
  generic configError rendering to renderUnavailable_FlagFalse(),
  which cites SPEC-002 FR-P12 and SPEC-005 §11.5. In-memory
  fetch-spy harness confirmed all four non-true values issue only
  /portal-config.json and make zero subsequent network calls.

- C.4 (stale-config notice unreachable through real UI): CLOSED.
  submitSignIn() no longer resets state.authFailBySurface on retry;
  the counter is reset only on a successful authenticated 2xx
  (per-surface) and on explicit signOut(). Two-retry harness
  confirmed first 403 shows only the identical sign-in rejection
  copy and second consecutive 403 on the same surface adds the
  misconfig notice while preserving the rejection copy.

Round 2 sweep of Categories A + C found 0 new findings. Round 1's
QUESTION (B.5 — autocomplete=off on the provider_token input) is
accepted as the deliberate privacy-preserving default per the
recommendation; not re-litigated.

Phase 1A readiness: READY TO COMMIT (already committed in 3cd7787
with the fixes folded in; this commit closes the audit-loop
artifact trail).

Artifact: specs/SPEC-014-impl-audit.md (round-2 section appended).
Re-audit prompt: specs/AUDIT_SPEC_014_IMPL_PHASE_1A_R2_PROMPT.md
(new file; same shape as SPEC-013 IMPL R2 prompts).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1B of SPEC-014 v0.8 per BUILD_SPEC_014_IMPL_PHASE_1B_PROMPT.md.
Extends the Phase 1A bundle with Surface B (Setup & Updates):

- B.1 requirements grid (4 cards, SPEC-003 §5 / FR-D1 verbatim).
- B.1a RAM-to-model sizing card (FR-D2 + FR-D2.1; presented as
  a hint with footer note).
- B.2 numbered setup steps (3 cards, each a copy-to-clipboard CTA):
  - Step 1 install.sh one-liner (FR-C2).
  - Step 2 macprovider-cli status (FR-C4 / §6.2).
  - Step 3 macprovider-cli autotune (SPEC-013 §6 / NFR-4) — no
    autotune banner, only the CTA.
- B.3 GitHub Releases feed:
  - 5 min in-memory cache TTL, fetch on first Surface B mount.
  - X-RateLimit-Remaining: 0 → loud fallback notice; previously
    cached list continues to render.
  - fetch() rejection (CORS / network) → loud user-visible notice
    naming SPEC-014 Open Q2.
  - Non-2xx → HTTP <N> from GitHub Releases notice.
  - Up to 12 entries; tag_name (fallback name) in monospace,
    published_at sliced to YYYY-MM-DD, <details><pre> for
    plain-text body (no markdown render of remote content,
    no innerHTML of remote data), per-entry copy-to-clipboard
    CTA for macprovider-cli update.
  - No "currently installed" badge (DEFERRED to v0.2, Open Q5).
  - Never reads Access-Control-Allow-Origin as application data.

- B.4 coordinator broadcasts panel NOT RENDERED (DEFERRED, Open Q5).

Phase 1A invariants preserved: AUTH-3 fail-CLOSED loader, AUTH-2
401/403/404 identical copy, stale-config guard, same-origin
coordinator routes, in-memory-only session, no remote command
execution. Sign-out now also clears state.releases.

Files:
- frontdoor/provider-portal/index.html (extended ~200 lines for
  renderSetup + releasesFetch + B-section CSS).
- frontdoor/provider-portal/README.md (phase-status update).
- specs/AUDIT_SPEC_014_IMPL_PHASE_1B_PROMPT.md (NEW; IMPL audit
  prompt fired against this commit).
- specs/AUDIT_SPEC_014_IMPL_PHASE_1B_R2_PROMPT.md (NEW; round-2
  closure-verification prompt).
- specs/SPEC-014-impl-audit.md (appended with Phase 1B round 1
  and round 2 sections).

IMPL audit:
- Round 1: 0 CRITICAL / 0 HIGH / 2 MEDIUM / 0 MINOR / 0 QUESTION.
  - C.4: Step 3 autotune cite incorrectly referenced SPEC-003 §6.2
    (which lists serve/self-test/status/update/uninstall, NOT
    autotune). Fix: keep only SPEC-013 §6 / NFR-4.
  - H.1: Phase 1B CSS added raw #0a0b0e literals for .snippet code
    and .release-card pre.rel-body. Fix: replace with var(--bg).
- Round 2: both MEDIUM CLOSED, 0 new findings.
- Phase 1B readiness: READY TO COMMIT (this commit).

Per memory: feedback-build-audit-loop. Per BUILD prompt's
single-PR plan, Phases 1A/1B/1C all land on the same branch
(feat/spec-014-provider-portal) and ship as a single PR after
Phase 1C LOCKs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1C of SPEC-014 v0.8 per BUILD_SPEC_014_IMPL_PHASE_1C_PROMPT.md.
Lands the final three surfaces and the AC 8(b)+8(f) build-time
grep guard. With this commit, SPEC-014 v0.1 is feature-complete on
this branch — ready to open the single PR after audit gates land.

Surface C (Earn):
- C.1 credit totals row (3 cards) reusing state.earn from Phase 1A:
  Lifetime credits / Current window / Last payout-ready window.
  Integer credits per SPEC-005 §11.4; no fiat conversion, no $,
  no "withdrawable balance" label.
- C.2 fiat-payout card: literal text "Fiat payout rail not yet
  specified — future spec." citing SPEC-005 §1.3 / §2.1 D1 +
  Open Q3. No country selector, no Stripe, no bank-link CTA, no
  payout-now CTA.
- C.3 / C.4 NOT rendered (Open Q4 deferred).
- Sidebar mount on `earn` route warms earnFetch("earn") so the
  Phase 1A stale-config guard increments correctly on this surface.

Surface D (Monitoring):
- ONE placeholder card titled "Monitoring — coming after SPEC-002
  amendment" with three bullets naming Open Q5 + privacy-redaction
  policy. ZERO network requests issued by the renderer.

Surface E (Identity):
- ONE read-only card with four fields: provider_id (pasted),
  Tier (pool data), State (pool data), Coordinator base URL
  (state.cfg.coordinator_base_url). Footer cites hardware /
  runtime fields as deferred behind Open Q5 and rotation /
  removal behind Open Q6. NO rotate-token button, NO remove-
  machine button, NO notification opt-in toggles, NO hardware
  field. Mount issues NO new fetch.

Sidebar polish:
- Sign-out (already wired in Phase 1A + 1B) clears session,
  pool, earn, releases, authFailBySurface; stops all timers;
  re-renders to sign-in. Verified.
- API Docs link uses rel="noopener noreferrer" target="_blank".
- Mobile (<720 px) hamburger / scrim unchanged from Phase 1A.

check-bundle.sh (NEW):
- Build-time grep guard for AC 8(b) (privileged-key routes +
  privileged-key identifier) + AC 8(f) (single-machine copy
  hygiene). Exits 0 clean / 1 found / 2 missing.
- Self-protection: EVERY prohibited literal in the script source
  (comments, variable assignments, echo messages, regex
  assignments) is split via Bash string concatenation so an
  external scan with the same grep patterns the script enforces
  against the bundle produces zero matches in the script itself.
  This pattern is now uniform across op_routes, op_key_pat,
  multi_machine, and the failure-message labels.
- README documents the script + CI hook + deploy steps.

IMPL audit:
- Round 1: 0 CRITICAL / 0 HIGH / 1 MEDIUM / 0 MINOR / 0 QUESTION.
  - E.5: check-bundle.sh source contained literal `operator-key` /
    `operator_key` in comments and echo messages (only the op_routes
    array was split; the comments / regex assignment / failure
    messages were not). Fix: split every prohibited literal via
    string concatenation; rename failure-message labels to
    `priv""ileged-key route` / `priv""ileged key identifier`.
- Round 2: E.5 CLOSED, 0 new findings. check-bundle.sh PASSES.
  Single-PR readiness: READY TO OPEN PR.

Files:
- frontdoor/provider-portal/index.html (extended ~150 lines for
  renderEarn + renderMonitoring + renderIdentity + Surface C/D/E
  CSS).
- frontdoor/provider-portal/check-bundle.sh (NEW, 85 lines,
  executable).
- frontdoor/provider-portal/README.md (extended with deploy steps,
  CI hook, auth model summary, Phase 1C status).
- specs/AUDIT_SPEC_014_IMPL_PHASE_1C_PROMPT.md (NEW; IMPL audit
  prompt fired against this commit).
- specs/AUDIT_SPEC_014_IMPL_PHASE_1C_R2_PROMPT.md (NEW; round 2
  closure verification prompt).
- specs/SPEC-014-impl-audit.md (appended with Phase 1C round 1
  and round 2 sections).

Per memory: feedback-build-audit-loop. The single PR opens after
this commit lands and `feat/spec-014-provider-portal` is ready to
push.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Augustas11 Augustas11 merged commit 7dba719 into main Jun 21, 2026
5 checks passed
@Augustas11 Augustas11 deleted the feat/spec-014-provider-portal branch June 21, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant