Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .agents/session-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,67 @@ To keep this file out of version control, add `.agents/session-log.md` to
- AGENTS.md's logging convention doesn't match the codebase (no logger module, no
eslint-no-console config) — either adopt a structured logger repo-wide or amend
AGENTS.md; qodo compliance rule 960794 will keep firing until one happens.

---

## 2026-06-09 — hexagen tooling repair (branch fix/hexagen-tooling, no PR yet)

- **Mode:** Implementer
- **Changes:**
- Bumped @hexagen-monaco/sync + arch-linter ^0.4.0 → ^0.6.0 (root cause: the
wizard wrote manifest.yaml with `workspaceTemplate`, a key only parsed from
0.6.0 on, while scaffolding ^0.4.0 pins — every hexagen command failed at load).
- Reconciled .architecture/ with repo reality: value_objects → value-objects
layer naming; dropped the two deleted external-service-client.out-port stubs;
declared adapter-context depends_on CampaignOrchestration; whitelisted
@campaignfoundry/CampaignOrchestration in invariants/linter-config.yaml
(the linter reads invariants, not manifest depends_on).
- Ran the first successful `yarn sync` (verified in a throwaway clone first):
removed shared's two empty placeholder barrels + parent re-exports, added
adapter barrels (CreativeGeneration's now exports fonts/safe-path too), empty
application skeletons, `"dependencies": {}` in shared/package.json.
Second sync is byte-level idempotent; all gates green (287 tests, 100% cov).
- Gitignored SYNC-MIGRATION-REPORT.md (per-run artifact).
- **Decisions:**
- lint:arch is green; templates:validate works ("no templates installed").
- Did NOT wire CI gates: at 0.6.0 every failure exits 0 (manifest parse failure,
arch violations) — gating would pass vacuously. Blocked on upstream fix.
- **Left open (upstream, hexagen-monaco):**
- Scaffolder must pin the CLI version whose schema it writes (the root cause).
- Exit codes: sync + arch validate exit 0 on every failure mode.
- --dry-run is not read-only: it deleted legacy empty barrels and wrote the
migration report (repeatable until converged).
- Dry-run planner + counters mislabel unconditional same-content rewrites as
create/update (43 "would" lines on a fully converged tree) — unusable as a
drift detector until fixed.
- Failure rollback runs `git reset --hard && git clean -fd` in the consumer repo.
- Then: release 0.6.1, bump pins here, wire sync:dry + lint:arch into CI.

---

## 2026-06-12 — hexagen 0.7.0 + CI architecture gates (branch fix/hexagen-tooling)

- **Mode:** Implementer
- **Changes:**
- Bumped @hexagen-monaco/sync + arch-linter ^0.6.0 → ^0.7.0 — the upstream
release that fixed everything the 2026-06-09 entry left open: honest exit
codes, read-only dry-run, truthful op counts, a `--check` drift mode, and
journaled scoped rollback (no more git-reset against this repo).
- Accepted yarn-4's normalized shared/package.json: install strips the empty
`"dependencies": {}` that 0.6.0's sync kept re-adding; 0.7.0 emits the
block only when non-empty, so the install↔sync churn loop is dead.
- Added the `sync:check` script and wired CI: `yarn install --immutable`
(lockfile is committed) + two fail-fast gates ahead of the build —
`sync:check` (drift) and `lint:arch`.
- **Decisions:**
- Gates went straight to `sync --check` rather than landing `sync:dry` first:
0.7.0 shipped both upstream hardening waves at once, so the interim step
had no window in which it was the best available gate.
- Probed the gate in both directions before trusting it: converged tree →
exit 0 / `Total ops : 0`; deleted generated barrel → exit 1 / "Drift
detected: 1 pending change(s)". Non-vacuous, unlike 0.6.0.
- **Left open:**
- setup-node's yarn cache is still disabled (TODO in ci.yml) — enabling it
requires corepack BEFORE setup-node (yarn-4 probe gotcha); separate change.
- Cosmetic upstream nit: dry-run logs each planned barrel op twice (counted
once — the summary table and exit code are correct).
6 changes: 6 additions & 0 deletions .architecture/invariants/linter-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
global_whitelist:
- "@campaignfoundry/shared"
- "@campaignfoundry/shared/**"
# CampaignOrchestration owns the ports (ImageGeneratorPort, CompositorPort, …);
# adapter packages import those interfaces to implement them — edges depending
# on the core, per .agents/architecture.md. Only the root entrypoint is
# whitelisted: ports/types are re-exported through it and package.json exposes
# no other subpath, so there is no deep-import surface to exempt.
- "@campaignfoundry/CampaignOrchestration"

test_double_rules:
allowed_cross_package_imports: true
11 changes: 6 additions & 5 deletions .architecture/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ generator:
folder: src/domain
subfolders:
- entities
- value_objects
- value-objects
application:
folder: src/application
subfolders:
Expand Down Expand Up @@ -148,6 +148,7 @@ bounded_contexts:
canvas compositing. Has no knowledge of CampaignBrief or use-case logic.
depends_on:
- shared
- CampaignOrchestration
uiFramework: Next.js
apiFramework: Express
layers:
Expand All @@ -159,8 +160,7 @@ bounded_contexts:
use_cases: []
ports:
in: []
out:
- external-service-client.out-port.ts
out: []
infrastructure:
adapters: []
- name: GovernanceAndCompliance
Expand All @@ -170,6 +170,7 @@ bounded_contexts:
safety and visual brand adherence.
depends_on:
- shared
- CampaignOrchestration
uiFramework: Next.js
apiFramework: Express
layers:
Expand All @@ -191,6 +192,7 @@ bounded_contexts:
no domain logic and is pure infrastructure.
depends_on:
- shared
- CampaignOrchestration
uiFramework: Next.js
apiFramework: Express
layers:
Expand All @@ -202,7 +204,6 @@ bounded_contexts:
use_cases: []
ports:
in: []
out:
- external-service-client.out-port.ts
out: []
infrastructure:
adapters: []
53 changes: 37 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,59 @@ jobs:
name: Build, Typecheck, Lint & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: actions/setup-node@v4
with:
node-version: "22"
# No package-manager cache here — actions/setup-node's cache requires a
# committed lockfile and fails without one. The Turbo cache below covers
# task outputs; re-enable the setup-node cache once you commit yarn.lock.

# Corepack activates the package manager pinned in package.json
# (`packageManager`). Without it, the runner's default Yarn (Classic)
# can't honor a Yarn-4 project. See SETUP.md.
# Corepack ships with the runner's pre-installed Node and must be enabled
# BEFORE setup-node: the `cache: yarn` step below probes the cache folder
# with whatever `yarn` is on PATH, and without Corepack that's Yarn Classic
# — which reports the wrong folder and fails the cache step. Enabling here
# installs the Yarn-4 shim (version read from package.json `packageManager`)
# so the probe resolves Berry's cache folder. See SETUP.md.
- name: Enable Corepack
run: corepack enable

- uses: actions/setup-node@v5
with:
node-version: "22"
# yarn.lock is committed, so setup-node keys its cache on it. Corepack
# (above) makes the probed folder Berry's global cache
# (enableGlobalCache: true → ~/.yarn/berry/cache). A wrong/empty cache
# only costs a re-download — `install --immutable` stays the source of
# truth — so this can never turn a green build red.
cache: "yarn"

# Read the pinned version from package.json's `packageManager` at runtime
# so CI can never drift from what the project declares (no baked version).
# Runs under the Node setup-node just installed; the shim from Enable
# Corepack stays on PATH (Node 22 ships no competing `yarn`).
- name: Prepare package manager
run: |
corepack prepare "$(node -p 'require("./package.json").packageManager')" --activate

# First run has no committed lockfile, so install is NOT immutable.
# After you commit yarn.lock, switch this to `yarn install --immutable`
# (npm: `npm ci`; pnpm: `pnpm install --frozen-lockfile`). See SETUP.md.
# yarn.lock is committed, so install is immutable: CI fails on a stale
# lockfile instead of silently rewriting it. This also protects the
# sync --check step below — its clean-tree preflight would otherwise
# trip on an install-mutated lockfile and mask the real drift signal.
- name: Install dependencies
run: "yarn install"
run: "yarn install --immutable"

# Hexagen architecture gates (require >=0.7.0 — earlier CLIs exited 0 on
# every failure mode, so gating was vacuous; see .agents/session-log.md,
# 2026-06-09 entry). `sync --check` is read-only and exits 1 iff the
# committed tree drifted from what .architecture/manifest.yaml generates;
# `arch validate` enforces the layer/import rules. Both are sub-second,
# hence ahead of the build for fail-fast.
- name: Architecture drift gate (hexagen sync --check)
run: "yarn sync:check"

- name: Architecture lint (hexagen arch validate)
run: "yarn lint:arch"

# Turbo caches task outputs keyed by input hash, so unchanged packages are
# skipped on warm runs (cache_strategy = turbo-cache). Set TURBO_TOKEN
# and TURBO_TEAM below for the cross-run remote cache.
- name: Restore Turbo cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ coverage/
*.log
.DS_Store

# hexagen sync writes a fresh run log every invocation — an artifact, not source
SYNC-MIGRATION-REPORT.md

# Generated creative output (binaries; see README) — anchored so the Nitro
# `server/routes/output/` source dir is NOT ignored.
/output/
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
"clean": "turbo clean",
"sync": "hexagen sync",
"sync:dry": "hexagen sync --dry-run",
"sync:check": "hexagen sync --check",
"sync:force": "hexagen sync --force",
"lint:arch": "hexagen arch validate",
"templates:add": "hexagen add",
"templates:validate": "hexagen validate-templates",
"format": "prettier --write \"**/*.{ts,tsx,md}\""
},
"devDependencies": {
"@hexagen-monaco/arch-linter": "^0.4.0",
"@hexagen-monaco/sync": "^0.4.0",
"@hexagen-monaco/arch-linter": "^0.8.0",
"@hexagen-monaco/sync": "^0.8.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
Expand Down
Empty file.
3 changes: 3 additions & 0 deletions packages/CreativeGeneration/src/application/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @generated by @hexagen/sync

export {};
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @generated by @hexagen/sync

export * from "./AssetReusingImageGenerator.js";
export * from "./canvas-util.js";
export * from "./FireflyImageGenerator.js";
export * from "./GeminiImageGenerator.js";
export * from "./NodeCanvasCompositor.js";
export * from "./OpenRouterImageGenerator.js";
export * from "./ProceduralBackgroundGenerator.js";
9 changes: 3 additions & 6 deletions packages/CreativeGeneration/src/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// @generated by @hexagen/sync

export * from "./adapters/AssetReusingImageGenerator.js";
export * from "./adapters/FireflyImageGenerator.js";
export * from "./adapters/GeminiImageGenerator.js";
export * from "./adapters/NodeCanvasCompositor.js";
export * from "./adapters/OpenRouterImageGenerator.js";
export * from "./adapters/ProceduralBackgroundGenerator.js";
export * from "./adapters/index.js";
export * from "./fonts.js";
export * from "./safe-path.js";
3 changes: 3 additions & 0 deletions packages/Distribution/src/application/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @generated by @hexagen/sync

export {};
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions packages/Distribution/src/infrastructure/adapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @generated by @hexagen/sync

export * from "./FileSystemExporter.js";
2 changes: 1 addition & 1 deletion packages/Distribution/src/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// @generated by @hexagen/sync

export * from "./adapters/FileSystemExporter.js";
export * from "./adapters/index.js";
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @generated by @hexagen/sync

export * from "./BrandComplianceChecker.js";
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// @generated by @hexagen/sync

export * from "./adapters/BrandComplianceChecker.js";
export * from "./adapters/index.js";
Empty file.
Empty file.
Empty file.
Empty file.
1 change: 0 additions & 1 deletion packages/shared/src/domain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@

export * from "./error-message.js";
export * from "./result.js";
export * from "./value-objects/index.js";
Empty file.
3 changes: 0 additions & 3 deletions packages/shared/src/domain/value-objects/index.ts

This file was deleted.

Empty file.
3 changes: 0 additions & 3 deletions packages/shared/src/infrastructure/adapters/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/shared/src/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @generated by @hexagen/sync

export * from "./adapters/index.js";
export * from "./project-root.js";
20 changes: 10 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -615,29 +615,29 @@ __metadata:
languageName: node
linkType: hard

"@hexagen-monaco/arch-linter@npm:^0.4.0":
version: 0.4.2
resolution: "@hexagen-monaco/arch-linter@npm:0.4.2"
"@hexagen-monaco/arch-linter@npm:^0.8.0":
version: 0.8.0
resolution: "@hexagen-monaco/arch-linter@npm:0.8.0"
dependencies:
js-yaml: "npm:^4.1.0"
ts-morph: "npm:^27.0.2"
zod: "npm:^3.23.8"
bin:
hexagen-lint: dist/index.js
checksum: 10c0/12818fe3ac2ce438a151b28e8e8ee645f6f7efb816999f40dbf518816a6b45b3b7629cfd8eabdc43f2270a039aa514638484b8033250e796de891633c32f78e5
checksum: 10c0/b58f0ec4957bfd7cf76227f3390953505f449b796daaf8c2d2ad8bf32711754b3c812f74c59c2f8e62366fa3bac3c113edabfc15188a40e23d3c58ddfe963365
languageName: node
linkType: hard

"@hexagen-monaco/sync@npm:^0.4.0":
version: 0.4.2
resolution: "@hexagen-monaco/sync@npm:0.4.2"
"@hexagen-monaco/sync@npm:^0.8.0":
version: 0.8.0
resolution: "@hexagen-monaco/sync@npm:0.8.0"
dependencies:
commander: "npm:^14.0.3"
js-yaml: "npm:^4.1.0"
ts-morph: "npm:^22.0.0"
bin:
hexagen: dist/cli.js
checksum: 10c0/317917146b1e7aa01f6bead0ae635cd50218cacb7800f5b9ea96673dfac5f13a385914c5466ca401144b93c6024d99ac26e2ddf335d5547257eb2f6a54ecd394
checksum: 10c0/59e0d6a44c240e6ccc4395cb5bec6f845f78cc3fa75823a917577742828848eb73d0286773af9f9c26e90dee6ff4a9c8ae0f9cb69cd950941f38e49522784e70
languageName: node
linkType: hard

Expand Down Expand Up @@ -2989,8 +2989,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "campaign-foundry@workspace:."
dependencies:
"@hexagen-monaco/arch-linter": "npm:^0.4.0"
"@hexagen-monaco/sync": "npm:^0.4.0"
"@hexagen-monaco/arch-linter": "npm:^0.8.0"
"@hexagen-monaco/sync": "npm:^0.8.0"
"@testing-library/dom": "npm:^10.4.1"
"@testing-library/react": "npm:^16.3.2"
"@testing-library/user-event": "npm:^14.6.1"
Expand Down
Loading