chore(governance): onboard governance-sync + publish-expert - #294
Conversation
Incremental FuzeSDLC bootstrap (scripts/sdlc-bootstrap.sh). Adds only what was missing: - governance-sync.yml — every PR reconciles this repo's managed files (the manifest's agent subset + the agent-templates framework) against the FuzeSDLC canonical at its baselineRef, so no PR merges against stale policy. SELF-CONTAINED (no cross-repo `uses:`, which cannot resolve against the private FuzeSDLC and would red the whole run). Skips with a notice until the read-only FUZESDLC_DEPLOY_KEY secret is set — it cannot break CI. - publish-expert.yml — publishes THIS repo's own <repo>-expert to the FuzeSDLC hub as an agent-sync PR on merge to main, so consuming repos stop carrying drifting hand-copies. Skips until FUZESDLC_AGENT_PUSH_TOKEN is set. Both are inert until their secrets exist. See FuzeSDLC governance/agent-ownership.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
| - package-ecosystem: github-actions | ||
| directory: "/" | ||
| schedule: { interval: weekly } | ||
| commit-message: { prefix: "ci(deps)" } | ||
| labels: ["dependencies", "github-actions"] |
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout (PR head) | ||
| uses: actions/checkout@v4 |
|
|
||
| - name: Fetch FuzeSDLC canonical (read-only key) | ||
| if: steps.guard.outputs.ok == 'true' | ||
| uses: actions/checkout@v4 |
| ssh-key: ${{ secrets.FUZESDLC_DEPLOY_KEY }} | ||
| path: .fuzesdlc-canonical | ||
|
|
||
| - uses: actions/setup-python@v5 |
| publish: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 |
Root causeThe Playwright FixAdded
In production the standalone security-service owns this surface. In CI (monolith only) this shim bridges the gap without requiring a second process. TypeScript build passes cleanly. Fixes the failing Generated with Claude Code |
…anded-branch detector
`claude-auto-pr.yml` has never opened a pull request, and cannot. The repo sets
`can_approve_pull_request_reviews: false`, so `gh pr create` from a workflow fails
with "GitHub Actions is not permitted to create or approve pull requests".
Every green run was the early-exit path ("PR already open") — the agent had
already opened its own PR. It ran the create path only when genuinely needed, and
failed. A check that passes when its work is already done by someone else, and
fails only when actually asked to work, proves nothing. It went green on this very
branch after a re-run, purely because a PR had appeared in between.
The permission stays OFF deliberately: GitHub bundles create-PR and approve-PR into
one toggle, and master is deploy-on-push with required reviews, so granting it
would give any workflow a self-approval path to prod. An un-bypassable review gate
beats auto-PR convenience; wire a scoped PAT/App token if auto-PR is ever needed.
So the workflow now does what it actually can: detect a branch with commits and no
PR and fail LOUDLY with the real remedy, so a dead agent's work is salvaged rather
than silently reaped by governance-nightly. It still attempts create first, so it
starts working unchanged if the permission is ever granted.
CLAUDE.md claimed all four agent prefixes auto-PR "the moment they are pushed to",
and that the branch self-resolves with no human. False for the life of the
workflow. Corrected: the agent opens its own PR; nothing does it for you.
Refs #294
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session-Id: f636c22e-1cd7-401e-8843-97e3e3a4ba01
…ing nothing
email-service is enabled in prod, its pod is green, and it has never delivered a
single message. `services/email-service/src/config.ts` reads SMTP_HOST with an
in-code fallback to `localhost:1025` (a dev mailhog), and the chart wired no SMTP
env at all — so every message was accepted and silently dropped. Two features have
been live-dead behind that fallback since they shipped:
- signup email verification (gated off, and unusable if turned on)
- password reset — NOT gated: passwordResetEnabled() only checks
EMAIL_SERVICE_URL, which IS wired, so it mints reset tokens and mails them
into the void. It has been silently broken in prod, not merely disabled.
Wire SMTP properly: host/port/secure from values (non-secret), SMTP_USER/SMTP_PASS
from the SealedSecret as HARD secretKeyRefs on the smtp provider path. Hard, not
optional, deliberately — an authenticated relay rejects anonymous mail, so a
missing credential must stop the pod at start (loud) rather than degrade into
dropping mail at runtime (silent). Local/dev keeps the mailhog fallback by leaving
host empty.
Guard the coupling instead of documenting it. values-prod said in prose that
requireEmailVerification "MUST stay false" until a sender is proven. Prose is not a
guard, and this is the session's recurring defect: two sources of truth that must
agree, with nothing checking them. The chart now FAILS TO RENDER when
requireEmailVerification is true while smtp.host is empty — deriving the
requirement from the actual flag rather than restating it. Turning verification on
with no deliverable sender would lock out every new signup.
Verified in all three directions:
A. prod as-is (off, no host) → renders, 0 SMTP env
B. on + no host → helm template FAILS with the reason
C. host set → renders with all 5 SMTP env vars
helm lint: 0 failed.
Owner-only step remains: seal SMTP_USER + SMTP_PASS (Zoho app password), then set
the host, then PROVE delivery, then flip verification — in that order, documented
in SEAL_PROD_SECRETS.md. Password reset revives at the proof step; it needs no flag.
Also commits the approved design-first UI pipeline plan to docs/planning/, stamped
with what has since been resolved (repo is public, Pages enabled, Actions
create-PR confirmed off by design, product-designer landed).
Refs #294
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session-Id: f636c22e-1cd7-401e-8843-97e3e3a4ba01
…PenPot gate (#302) CLAUDE.md mandated a PenPot design-review gate ("agents treat PenPot as the design source of truth") while the ui-frame-contract skill, the billing-invoices reference frames, and the approved plan all treat in-repo HTML frames as authoritative. Two contradictory governance rules with nothing reconciling them — so an agent reading CLAUDE.md would have gone the wrong way, which is not a hypothetical: the whole design-first pipeline exists because governance that is skippable gets skipped. PenPot is parked by owner decision. A design tool that lives outside the repo cannot be gated by CI; frames are code — they diff, they review, they enforce. Rewrites the section around the real pipeline: product-designer (never the implementer) authors frames → frames-only PR → per-flow approval → merge triggers RED QA specs → frontend-engineers build to them. Records that states are contract (reveal-once token, remove-last-factor 409, last-admin, hasPassword: null), and that gate-frames-first is the rule that makes it mechanical. Refs #294 Claude-Session-Id: f636c22e-1cd7-401e-8843-97e3e3a4ba01 Co-authored-by: fuzeone-bot[bot] <fuzeone-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#312) The frames published fine but had no way to act on them — the reviewer could walk a flow and had nowhere to approve or reject it. The approval mechanism was deferred; this builds the first, manual increment. build-frames-site.mjs now injects a fixed approval bar into EVERY published .html of a feature (not just the index), derived from the manifest's build.flows. Each pending flow gets Approve / Reject buttons that open a prefilled GitHub issue (feature, flow, route, decision, stamp) — a durable, auditable record a workflow or maintainer reads to flip the per-flow `approved`. Approved flows show their state and drop the buttons. Also fixes approvalOf(): it read per-flow approval from manifest.frames, but the source of truth is build.flows — so the index pills were reading the wrong field and showing every multi-flow feature as unapproved-by-default regardless. Now both the index pills and the in-frame bar read build.flows via one flowsOf() helper, so they can't disagree. Prefill uses plain query params (title/body) — the only issue prefill that is 100% reliable. Buttons open in a new tab so the reviewer keeps their place. Follow-up (not here): the design-approval workflow that reads the issue and flips `approved` automatically; until it lands, a maintainer flips it. Refs #294 Claude-Session-Id: f636c22e-1cd7-401e-8843-97e3e3a4ba01 Co-authored-by: fuzeone-bot[bot] <fuzeone-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Incremental FuzeSDLC bootstrap — adds only what was missing in this repo.
governance-sync.yml— on every PR, reconciles this repo's managed files (the manifest's agent subset + theagent-templatesframework) against the FuzeSDLC canonical at itsbaselineRef, so no PR merges against stale policy. Self-contained (no cross-repouses:, which cannot resolve against the private FuzeSDLC and would red the whole run).publish-expert.yml— publishes this repo's own<repo>-expertto the FuzeSDLC hub as anagent-syncPR on merge tomain, so consuming repos stop carrying drifting hand-copies. The hub'sagent-sync-guardverifies the PR only touches this repo's own files.Both are inert until their secrets exist (
FUZESDLC_DEPLOY_KEY/FUZESDLC_AGENT_PUSH_TOKEN) — they skip with a notice and cannot break CI.Model: FuzeSDLC
governance/agent-ownership.md. Context: FuzeSDLC#41, #42.