Skip to content

feat(e90): dev-environment hardening — config consolidation, CI gates, tooling debt - #311

Merged
danielvm-git merged 33 commits into
mainfrom
feat/e90-dev-environment-hardening
Nov 6, 2026
Merged

danielvm-git merged 33 commits into
mainfrom
feat/e90-dev-environment-hardening

Conversation

@danielvm-git

@danielvm-git danielvm-git commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

User description

Summary

Epic e90 — Dev-Environment Hardening (WSJF 9.0), built end-to-end and verified.

What ships

  • e90s01 required-env gate (BIGBASE_ROOT_ENCRYPTION_KEY) — fixture-testable, enforced in pre-commit + CI
  • e90s02 single conflict-marker gate (scripts/check-conflict-markers.sh) backing CI + pre-commit; stray .gitignore <stdin> pattern removed
  • e90s03 AGENTS.md ctxo mandate demoted to preferred-when-fresh
  • e90s04 -race CI job + UI lint/typecheck/test/build gate; fixed a real defect the race job exposed — drain transitions now reach status_history (forceStatus + idempotent drain guard)
  • e90s05 .mcp.json canonical source + make mcp/make mcp-check
  • e90s06 AGENTS.md single source; CLAUDE.md/GEMINI.md symlinks
  • e90s07 version drift gate extended to CI pins + toolchain.toml floor
  • e90s08 dependabot groups + rebase-before-push discipline
  • e90s09 async-assert poll guideline + waitForStatusHistory canonical example

Also carries 5 prior readiness-gates commits (all chore:) that were merged to local main but never pushed.

Test plan

  • Preflight green (go vet + go test ./... + gosec + build + codeql + gitleaks)
  • UI: eslint, tsc, vitest (755), build — green
  • Race suite (deploy/functions/realtime/monitoring) green, incl. -count=3 and -count=5 stress
  • 24 gate-script tests green (wired into CI verify)
  • trace-stories --strict exit 0; 0 blind spots

Note on merge

This branch contains feat:/fix: commits, so merging will cause big-release to auto-publish a release and deploy.yml to auto-deploy to production. Flagged for confirmation before merge.


PR Type

Enhancement, Bug fix, Tests, Documentation


Description

  • Add reusable conflict/env/version gate scripts

  • Fix drain race with idempotent guard and history

  • Add gate-script tests wired into CI verify

  • Consolidate AGENTS.md; remove CLAUDE/GEMINI adapters

  • Add git hooks and Make targets


Diagram Walkthrough

flowchart LR
    A["Reusable gate scripts"] --> B["CI verify + pre-commit"]
    C["Drain idempotence + forceStatus"] --> D["status_history audit trail"]
    E["AGENTS.md consolidation"] --> F["CLAUDE/GEMINI removal"]
    G["Gate-script tests"] --> B
Loading

File Walkthrough

Relevant files
Bug fix
3 files
orchestrator.go
Idempotent drain guard and early draining transition         
+26/-6   
engine.go
forceStatus appends audit history under mutex                       
+39/-2   
deploy.go
Add draining map to prevent duplicate drains                         
+4/-0     
Tests
5 files
drain_test.go
Poll status history and orphan drain test                               
+66/-38 
check-conflict-markers.test.cjs
Pin conflict marker gate failure paths                                     
+93/-0   
check-required-env-documented.test.cjs
Pin env doc gate failure and skip paths                                   
+107/-0 
check-version-drift.test.cjs
Pin CI and toolchain version drift failures                           
+81/-0   
gen-mcp-configs.test.cjs
Verify canonical MCP adapter generation                                   
+45/-0   
Configuration changes
4 files
test-build-release.yml
Raise race timeout, reuse gates, run script tests               
+13/-7   
commit-msg
Enforce Conventional Commits and no AI attribution             
+34/-0   
pre-commit
Run conflict marker gate on commit                                             
+10/-0   
pre-push
Block manual pushes to protected main                                       
+22/-0   
Enhancement
5 files
check-conflict-markers.sh
Add reusable conflict marker gate script                                 
+40/-0   
check-required-env-documented.sh
Support fixture root for env gate                                               
+5/-1     
check-version-drift.sh
Extend drift checks to CI and toolchain pins                         
+55/-1   
trace-stories.sh
Restrict strict dark checks to active epic                             
+13/-3   
Makefile
Add build, test, script, and MCP targets                                 
+30/-0   
Documentation
3 files
AGENTS.md
Consolidate agent rules and demote ctxo mandate                   
+52/-1   
CONVENTIONS.md
Add commands, never-do list, async polling guidance           
+26/-0   
CLAUDE.md
Remove Claude-specific adapter in favor of AGENTS.md         
+0/-49   
Additional files
20 files
GEMINI.md +0/-41   
GEMINI.md +0/-41   
envresolver.go +1/-0     
export_test.go +6/-0     
state_lifecycle_test.go +1/-0     
projects.go +1/-0     
projects_test.go +1/-0     
manager.go +1/-0     
manager_test.go +1/-0     
secrets.go +1/-0     
secrets_test.go +1/-0     
env_vars.go +1/-0     
env_vars_test.go +1/-0     
gen-mcp-configs.sh +1/-0     
generate-agent-guide.sh +1/-0     
land-branch.sh +2/-0     
setup-dev.sh +1/-0     
verify-cwe-fixture-sync.sh +1/-0     
axe-scan.spec.ts +1/-0     
SecretsPage.tsx +1/-0     

BigBase Admin added 30 commits November 6, 2026 12:38
Fixtures a throwaway root via BIGBASE_ENV_DOC_ROOT so the gate can be
exercised against missing-key, missing-workflow and empty-declaration
cases instead of only the live repository.

Red: the gate ignores the override and dies at git rev-parse (exit 128).
GREEN for the e90s01 drift tests: BIGBASE_ENV_DOC_ROOT overrides the
git-derived root so missing-key and skip paths are testable without
touching the live .env.example. Default behaviour is unchanged.
Covers opening/separator/closing markers, non-anchored false positives,
and the CHANGELOG.md + specs/archive exemptions that the inline CI step
handles today.

Red: scripts/check-conflict-markers.sh does not exist yet (8/8 failing).
GREEN for the e90s02 marker tests. One implementation of the marker
contract (git-tracked scan + explicit-path mode) so CI and pre-commit
stop carrying copies of the same regex.
Replaces the inline git-grep copy in the verify job and adds the same
gate to pre-commit, so both paths share one implementation and one set
of exemptions.
Leftover from a conflict-resolution session; it matched nothing and
shadowed the intent of the surrounding dev-tooling block.
AGENTS.md demotes ctxo to optional-when-fresh, but the task table still
read "REQUIRED First Call" — the contradiction that made agents block on
a stale index. Also lands the setup-dev.sh onboarding script that sets
core.hooksPath and warms the index.
The -race CI job observed status=stopped with status_history frozen at
"running". Reproduces deterministically: draining a deployment with no
in-memory app entry records nothing in status_history.

Red: history stays empty (status written by a raw UPDATE in
stopDeployment).
GREEN for the app-less drain test. Two defects were hiding behind the
-race failure:

- stopDeployment() wrote status with a raw UPDATE, so force-stops
  (orphan drain, DELETE) never reached status_history. It now goes
  through forceStatus(), which appends the transition.
- drainDeployment() skipped the draining transition entirely when no
  in-memory app existed, and a second collect could force-stop a
  deployment while the first drain was still running. The drain intent
  is now recorded before the branch and duplicate drains are skipped.

Full -race suite for deploy/functions/realtime/monitoring is green.
scripts/gen-mcp-configs.sh tells contributors to run `make mcp`, but no
Makefile target existed. Also asserts opencode.jsonc still mirrors the
canonical .mcp.json server list.

Red: "No rule to make target `mcp'" (1 of 3 failing).
GREEN for the MCP adapter tests. The Makefile was an untracked scratch
file with no mcp target even though gen-mcp-configs.sh documents one;
track it with mcp/mcp-check wired to the canonical generator.
The async-assert guideline was correct but did not mention the deploy
audit trail, the case that actually flaked in the -race CI job: status is
committed before status_history, so readers must poll for the transition.
Also refreshes the generated conventions wiki.
AGENTS.md is the only agent instruction file; CLAUDE.md and GEMINI.md are
symlinks to it. Regenerates the OKF agent-guide pages from that source and
trace-tags the scripts that implement the e90 stories.
The drift script only checked prose. These fixtures assert the
configurations too: CI GO_VERSION/NODE_VERSION against go.mod/.nvmrc and
the toolchain.toml Go floor.

Red: 3 of 6 failing (no configuration checks yet).
GREEN for the configuration drift tests. Adds a BIGBASE_VERSION_ROOT
override, then compares the CI GO_VERSION/NODE_VERSION env pins and the
toolchain.toml Go floor with the declarations in go.mod and .nvmrc.
The new fixture tests (env-doc, conflict-marker, MCP adapter, version
drift) were only runnable locally. Wire them into verify so a gate that
silently stops detecting drift fails CI, and expose them as
`make test-scripts`.
audit-code follow-up: forceStatus read the current status outside the
mutex TransitionState uses for its history read-modify-write, so a
concurrent transition could land in between and leave the recorded
"from" stale. Read, write and append now share the same critical
section; deploy package stays green under -race.
request-review F-1: a bare "story:" tag on a file that does not obviously
implement the story reads as tag-padding. Both markers now name the
relationship so the trace matrix stays auditable.
request-review F-2: the script used relative paths with no root
resolution, so run outside the checkout it read nothing and exited 0 — a
green gate that checked nothing. It now resolves the root (override or
git rev-parse) and documents the loud-failure behaviour.
e90 grows past the flat-shard limit: nine stories, threat model, test
plan and per-task verify commands. Moves it to
specs/epics/e90-dev-environment-hardening/ with epic.yaml plus one spec
and one -tasks.yaml per story, updates release-plan.yaml to the capsule
form, and records the scoped e90 requirement set.
All nine stories are done in execution-status.yaml, the epic and its
release-plan entry read done, state.yaml carries the ten gate decisions
and the handoff to release-branch, and each story has a -verify.yaml with
a terminal verdict. Also refreshes the traceability matrix, blind-spot
report and spec drift report (0 blind spots, 1 reviewed drift link).
The deploy package sits at ~250-300s under -race on a loaded machine and
hit the old 300s per-package budget as a timeout panic. Bump -timeout to
600s (job still allows 20 minutes). One later 423s failure was not
reproduced across 10+ clean runs (count=2, count=3, count=5 stress) and
never produced a DATA RACE report; recorded in state.yaml decisions.
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The export GIT_BIGPOWERS_LAND=1 in this executed script does not persist to the caller's shell. The script exits after merging, so when the user follows the printed instruction to run git push origin main, the new .githooks/pre-push hook still sees GIT_BIGPOWERS_LAND unset and blocks the push. Either push from the script itself with the bypass set, or print the exact GIT_BIGPOWERS_LAND=1 git push origin main command.

export GIT_BIGPOWERS_LAND=1
echo "✅ Merged $BRANCH. Run 'git push origin main' to deploy."

@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Remove current branch push restriction

The current_branch == main condition blocks legitimate pushes from main to
non-protected targets such as tags (git push origin v1.0) or other branches.
Restrict the guard to the actual remote branch being pushed.

.githooks/pre-push [12]

-if [ "$remote_branch" = "$protected_branch" ] || [ "$current_branch" = "$protected_branch" ]; then
+if [ "$remote_branch" = "$protected_branch" ]; then
Suggestion importance[1-10]: 6

__

Why: The current-branch condition wrongly blocks pushes from main to non-protected refs such as tags or other branches. Removing it correctly limits the guard to pushes whose remote branch is main.

Low
Strip quotes from active epic ID

The regex captures the full scalar value from state.yaml, including surrounding
quotes if the active epic is written as "e90" or 'e90'. The subsequent
startswith(active_epic) then fails to match any story IDs, silently disabling the
dark-story gate. Strip surrounding quotes after capture.

scripts/trace-stories.sh [108-114]

 active_epic = None
 state_path = root / "specs" / "state.yaml"
 if state_path.is_file():
     m = re.search(r"^\s*active_epic(?:_id)?:\s*(\S+)", state_path.read_text(), re.M)
     if m:
-        active_epic = m.group(1).strip()
+        active_epic = m.group(1).strip().strip('"').strip("'")
 active_dark = [s for s in ordered if s["status"] == "Dark" and (not active_epic or s["story_id"].startswith(active_epic))]
Suggestion importance[1-10]: 5

__

Why: The regex can capture a quoted YAML scalar, causing startswith(active_epic) to fail and silently disabling the dark-story strict gate. The fix is correct, but it only matters when specs/state.yaml uses quotes around the epic id.

Low

@danielvm-git
danielvm-git merged commit 4eb8b7f into main Nov 6, 2026
17 checks passed
@danielvm-git
danielvm-git deleted the feat/e90-dev-environment-hardening branch November 6, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant