Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
782fa76
feat(agents): add domain documentation and issue tracker guidelines
DaneSpiritGOD Oct 18, 2026
88ab6c1
docs: add domain glossary and fork-local ADRs
DaneSpiritGOD Oct 19, 2026
a513bd8
chore: trigger ci on fork
DaneSpiritGOD Oct 19, 2026
f01a5ac
docs(adr): upstream changes land via a verified sync pull request
DaneSpiritGOD Oct 19, 2026
e6e7e0b
feat(md-web-cli): bundle pipeline and minimal render CLI
DaneSpiritGOD Oct 19, 2026
5c6546a
fix(md-web-cli): build bundle before tests so the CLI subprocess test…
DaneSpiritGOD Oct 19, 2026
5270da8
feat(md-web-cli): wechat-ready output and placeholder failure semantics
DaneSpiritGOD Oct 19, 2026
5db40a8
feat(md-web-cli): config file dialects, flag overrides, --raw and bod…
DaneSpiritGOD Oct 19, 2026
ca3f721
feat(oracle): workflow_dispatch browser Oracle rebuild via Playwright
DaneSpiritGOD Oct 19, 2026
66fe680
feat(oracle): semantic diff and tier 1 acceptance evidence
DaneSpiritGOD Oct 19, 2026
3e5ad58
fix(md-web-cli): semantic-diff tests read the committed oracle eviden…
DaneSpiritGOD Oct 19, 2026
5c90120
test(md-web-cli): golden snapshot + Tier 2 verify-snapshot gate (tick…
DaneSpiritGOD Oct 19, 2026
49913ec
feat(md-web-cli): OIDC publish workflow with registry-aware version r…
DaneSpiritGOD Oct 19, 2026
822c281
fix(oracle): collapse whitespace when comparing extracted CSS values
DaneSpiritGOD Oct 19, 2026
2a8ab40
ci(sync): weekly upstream sync workflow with verified sync PR (ticket…
DaneSpiritGOD Oct 19, 2026
488475f
fix(md-web-cli): review fixes - boolean flag argv handling, juice fal…
DaneSpiritGOD Oct 19, 2026
1ba7015
chore: ignore local temp/ scratch directory
DaneSpiritGOD Oct 20, 2026
112b409
fix(oracle): parse full color syntax in the semantic extractor
DaneSpiritGOD Oct 20, 2026
a902231
test(md-web-cli): replace blind test assertions with observable ones
DaneSpiritGOD Oct 20, 2026
cdb293a
test(md-web-cli): drop an assertion that could never fail
DaneSpiritGOD Oct 20, 2026
84a7a3b
fix(lint): re-ignore scripts to match upstream lint surface
DaneSpiritGOD Oct 21, 2026
fb08630
fix(md-web-cli): order type import before value import
DaneSpiritGOD Oct 21, 2026
2b2e5fc
chore(spike): run the browser Oracle headless on a GitHub runner
DaneSpiritGOD Oct 21, 2026
e5cceb1
feat(verify): make the Oracle a callable capability
DaneSpiritGOD Oct 22, 2026
9686548
test(md-web-cli): assert site-default parity between CLI and app
DaneSpiritGOD Oct 22, 2026
f157415
docs(adr): record the single verify gate and narrow the Oracle glossa…
DaneSpiritGOD Oct 22, 2026
1347468
feat(verify): one command that builds, captures, and compares byte-ex…
DaneSpiritGOD Oct 22, 2026
194abcd
test(verify): add an infrastructure-probe fixture
DaneSpiritGOD Oct 22, 2026
64387a9
feat(verify): accept a Designer config and project it to render keys
DaneSpiritGOD Oct 22, 2026
ef960aa
feat(verify): keep structural assertions and add a reverse-case self-…
DaneSpiritGOD Oct 22, 2026
c8ad1e2
ci: run verify as a non-blocking signal with a cached browser
DaneSpiritGOD Oct 22, 2026
c773bda
ci: switch publish and sync workflows to verify
DaneSpiritGOD Oct 22, 2026
a2c3fa6
docs(md-web-cli): consolidate docs and relocate the manual paste check
DaneSpiritGOD Oct 22, 2026
7dccaa9
chore(md-web-cli): retire the tier machinery, golden snapshot, and or…
DaneSpiritGOD Oct 22, 2026
01ae266
fix(verify): keep per-fixture artifact dirs and detect text-only prev…
DaneSpiritGOD Oct 22, 2026
59d74af
fix(verify): close review findings in the gate
DaneSpiritGOD Oct 22, 2026
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
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,34 @@ jobs:

- name: Run tests
run: pnpm run test

# The verify gate's browser is downloaded once per Playwright version and
# restored from cache on every later run.
- name: Resolve Playwright version
id: playwright
run: echo "version=$(node -p "require('playwright/package.json').version")" >> "$GITHUB_OUTPUT"

- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright.outputs.version }}

- name: Install Playwright Chromium
run: pnpm exec playwright install --with-deps chromium

# The config-projection acceptance needs a browser, so it runs here
# instead of in the fast suite. Blocking: it guards a real regression
# (an export's article content leaking into the comparison).
- name: Run browser-gated CLI tests
env:
MD_WEB_CLI_BROWSER_TESTS: '1'
run: pnpm --filter @dane.dai/md-web-cli exec vitest run tests/verify-config.test.ts

# TEMPORARY: non-blocking while the gate is red on purpose. The difference
# classes are visible in the log on every change. The transition to
# blocking is an explicit decision, recorded per
# docs/adr/0003-single-verify-gate.md ("The gate deliberately landed red").
- name: Verify rendering (non-blocking)
continue-on-error: true
run: pnpm wcli:verify
103 changes: 103 additions & 0 deletions .github/workflows/publish-md-web-cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: Publish md-web-cli

# Ticket #9: push to main runs the verify gate (which builds the md-web-cli
# bundle itself, captures a browser Oracle, and compares byte for byte) and,
# only when everything is green, publishes to npm via OIDC trusted publishing.
# Red runs publish nothing; failure notification is GitHub's built-in Actions
# email (account-level: Email + only failed workflows) — no notification
# secrets or steps here.
#
# While the gate is deliberately red (see docs/adr/0003-single-verify-gate.md),
# this workflow stays blocking on purpose: a red gate publishes nothing.
#
# DANE: before the first successful publish, configure the npmjs trusted
# publisher for @dane.dai/md-web-cli (npmjs.com → package/Automation settings):
# - package name: @dane.dai/md-web-cli
# - repository: DaneSpiritGOD/md
# - workflow filename: publish-md-web-cli.yml
# - environment: (leave empty — this workflow uses no GitHub environment)
# The very first publish is manual (trusted publisher cannot be configured
# before the package exists on npm); afterwards this workflow owns publishing.

on:
push:
branches: [main]

concurrency:
group: ci-publish
cancel-in-progress: false

permissions:
contents: read
id-token: write # OIDC trusted publishing — no NODE_AUTH_TOKEN anywhere below

jobs:
verify-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false

- name: Set up pnpm
uses: pnpm/setup@v3
with:
version: 12.14.0
runtime: node@22
cache: true
install: false

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Resolve Playwright version
id: playwright
run: echo "version=$(node -p "require('playwright/package.json').version")" >> "$GITHUB_OUTPUT"

- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright.outputs.version }}

- name: Install Playwright Chromium
run: pnpm exec playwright install --with-deps chromium

# Builds both workspaces itself (never a previously built bundle), captures
# a fresh Oracle, and compares byte for byte. Non-zero exits here publish
# nothing: every later step is skipped.
- name: Verify rendering (wcli:verify)
run: pnpm wcli:verify

- name: Run package unit tests
run: pnpm --filter @dane.dai/md-web-cli test

- name: Upgrade npm for OIDC trusted publishing
# Node 22 bundles npm 10.x; npm trusted publishing (id-token OIDC)
# requires npm >= 11.5.1.
run: npm install -g npm@latest

- name: Resolve publish version
id: resolve-version
working-directory: packages/md-web-cli
env:
# Same registry the gate/CI uses for reads; explicit so the repo
# .npmrc mirror cannot redirect version lookups.
NPM_CONFIG_REGISTRY: https://registry.npmjs.org
run: node scripts/resolve-publish-version.mjs

- name: Apply publish version
working-directory: packages/md-web-cli
env:
PUBLISH_VERSION: ${{ steps.resolve-version.outputs.version }}
run: npm version "$PUBLISH_VERSION" --no-git-tag-version

- name: Publish to npm (OIDC trusted publishing)
working-directory: packages/md-web-cli
env:
NPM_CONFIG_REGISTRY: https://registry.npmjs.org
# Deliberately NO NODE_AUTH_TOKEN: authentication is the job's
# id-token (npm provenance / trusted publishing).
NPM_CONFIG_PROVENANCE: 'true'
run: npm publish
208 changes: 208 additions & 0 deletions .github/workflows/sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
name: Sync upstream doocs/md

# Ticket #10: weekly cron + manual dispatch upstream sync.
#
# Flow: fetch upstream (doocs/md) → if upstream/main has commits not yet on
# main, merge them into the `sync/upstream` branch in this workspace → run the
# verify gate (same `pnpm wcli:verify` as publish-md-web-cli.yml, so the two
# never disagree about what passes) → push the branch and open — or
# force-update an already-open — PR into main whose body records the
# verification result rendered from this run's actual outcome, plus this run
# link. The human reviews the diff and merges manually; that merge is a real
# push to main and triggers the publish chain (publish-md-web-cli.yml)
# normally.
#
# The PR is created with GITHUB_TOKEN, so it carries no checks — events from
# the default token do not trigger workflows. The verification that already
# passed here, recorded in the PR body, is what the human merges on.
#
# Failure modes (all surface as job failure → GitHub's built-in Actions
# notification; no PR is opened, nothing is pushed):
# 1. Merge conflict — "Merge upstream main" step fails.
# 2. Build failure — the build inside `pnpm wcli:verify` fails.
# 3. Verify failure — `pnpm wcli:verify` exits non-zero (the gate is red).
#
# While the gate is deliberately red (docs/adr/0003-single-verify-gate.md),
# this workflow stays blocking on purpose: upstream merges are held until the
# known differences are worked through.
#
# No new upstream commits → job exits successfully, no PR, no branch change.

on:
schedule:
- cron: '0 3 * * 1' # every Monday 03:00 UTC
workflow_dispatch:

concurrency:
group: sync-upstream
cancel-in-progress: false

permissions:
contents: write # push / force-update the sync branch
pull-requests: write # open and update the sync PR

jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout main (full history)
uses: actions/checkout@v7
with:
ref: main
fetch-depth: 0 # merge + ancestry check + force-update need history
persist-credentials: true # GITHUB_TOKEN push access for the sync branch

- name: Fetch upstream
run: |
git remote add upstream https://github.com/doocs/md.git
git fetch upstream main --no-tags
git fetch origin main --no-tags

- name: Check for new upstream commits
id: upstream
run: |
UPSTREAM_HEAD="$(git rev-parse upstream/main)"
echo "head=${UPSTREAM_HEAD}" >> "$GITHUB_OUTPUT"
if git merge-base --is-ancestor "${UPSTREAM_HEAD}" origin/main; then
echo "new=false" >> "$GITHUB_OUTPUT"
echo "No new upstream commits (upstream/main ${UPSTREAM_HEAD} already contained in main)."
else
echo "new=true" >> "$GITHUB_OUTPUT"
echo "New upstream commits detected; range main..${UPSTREAM_HEAD}:"
git log --oneline origin/main.."${UPSTREAM_HEAD}" || true
fi

- name: Stop early — nothing to sync
if: steps.upstream.outputs.new != 'true'
run: echo "Upstream is already fully merged into main; nothing to do."

- name: Create sync branch from main
if: steps.upstream.outputs.new == 'true'
run: |
git checkout -B sync/upstream origin/main

- name: Merge upstream main
# Failure here = failure mode 1 (merge conflict): git exits non-zero,
# the job fails, GitHub notifies, no PR is opened, main is untouched.
if: steps.upstream.outputs.new == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git merge --no-edit "upstream/main" \
-m "chore: merge upstream doocs/md at $(git rev-parse upstream/main)"

- name: Set up pnpm
# Mirror publish-md-web-cli.yml so both workflows run identical toolchain.
if: steps.upstream.outputs.new == 'true'
uses: pnpm/setup@v3
with:
version: 12.14.0
runtime: node@22
cache: true
install: false

- name: Install dependencies
# Failure here is surfaced as a build failure (failure mode 2).
# Upstream may have changed dependencies, breaking the frozen lockfile;
# fall back to a plain install and commit the refreshed lockfile with
# the merge so the PR is self-consistent.
if: steps.upstream.outputs.new == 'true'
run: |
pnpm config set store-dir ~/.pnpm-store
if ! pnpm install --frozen-lockfile; then
echo "::warning::pnpm install --frozen-lockfile failed — retrying without frozen lockfile (upstream dependency change)"
pnpm install --no-frozen-lockfile
fi

- name: Resolve Playwright version
if: steps.upstream.outputs.new == 'true'
id: playwright
run: echo "version=$(node -p "require('playwright/package.json').version")" >> "$GITHUB_OUTPUT"

- name: Cache Playwright browsers
if: steps.upstream.outputs.new == 'true'
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright.outputs.version }}

- name: Install Playwright Chromium
if: steps.upstream.outputs.new == 'true'
run: pnpm exec playwright install --with-deps chromium

- name: Verify rendering (wcli:verify)
id: verify
# Failure here = failure mode 2 or 3: the build inside the gate or the
# comparison failed. Job fails, GitHub notifies, no PR is opened, main
# is untouched.
if: steps.upstream.outputs.new == 'true'
run: |
set +e
pnpm wcli:verify 2>&1 | tee verify.log
STATUS=${PIPESTATUS[0]}
set -e
if [ "$STATUS" -ne 0 ]; then
# Recorded so the PR body can never claim a success that did not
# happen; this step exits before any PR step runs.
echo "result=FAILED" >> "$GITHUB_OUTPUT"
echo "::error::pnpm wcli:verify failed — nothing was pushed and no PR was opened"
exit "$STATUS"
fi
echo "result=PASSED" >> "$GITHUB_OUTPUT"

- name: Run package unit tests
if: steps.upstream.outputs.new == 'true'
run: pnpm --filter @dane.dai/md-web-cli test

- name: Push sync branch
# force-with-lease: a second dispatch while the PR is open re-creates
# the branch from the latest main and force-updates it — the open PR
# follows the branch, no duplicate is created.
if: steps.upstream.outputs.new == 'true' && steps.verify.outputs.result == 'PASSED'
run: git push --force-with-lease origin sync/upstream

- name: Open or update sync pull request
if: steps.upstream.outputs.new == 'true' && steps.verify.outputs.result == 'PASSED'
env:
GH_TOKEN: ${{ github.token }}
RUN_LINK: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
UPSTREAM_HEAD: ${{ steps.upstream.outputs.head }}
VERIFY_RESULT: ${{ steps.verify.outputs.result }}
run: |
COMMIT_COUNT="$(git rev-list --count origin/main..upstream/main)"
RANGE="origin/main...${UPSTREAM_HEAD}"
# Rendered from the run's real outcome. A failed verification exits
# before this step, so this line can never claim a success that did
# not happen.
if [ "${VERIFY_RESULT}" = "PASSED" ]; then
VERIFY_LINE="✅ PASSED — \`pnpm wcli:verify\` (build + fresh Oracle + byte-exact comparison + structural assertions) and package unit tests are green in this workflow's sync workspace"
else
VERIFY_LINE="❌ ${VERIFY_RESULT:-NOT RUN} — \`pnpm wcli:verify\` did not pass; this pull request must not be merged"
fi
BODY=$(cat <<EOF
## Upstream sync: doocs/md

Merge upstream \`doocs/md\` (\`${UPSTREAM_HEAD}\`) into \`main\`.

- **Upstream range:** \`${RANGE}\` (${COMMIT_COUNT} commit(s)) ([upstream commits](https://github.com/doocs/md/commits/main)):
$(git log --oneline --no-decorate origin/main.."${UPSTREAM_HEAD}" | sed 's/^/ - /' | head -20)
- **Verification:** ${VERIFY_LINE} ([run link](${RUN_LINK}))
- **Verification run:** ${RUN_LINK}

> The PR is created with the workflow's own token, so it carries no
> checks. The verification recorded above is this run's actual
> result in the sync workspace — that is what you merge on. Merging this PR is a real
> push to \`main\` and triggers the publish chain
> (\`publish-md-web-cli.yml\`) normally.
EOF
)
if gh pr view sync/upstream --json state >/dev/null 2>&1; then
gh pr edit sync/upstream --title "chore: sync upstream doocs/md" --body "$BODY"
echo "Force-updated existing sync PR."
else
gh pr create \
--base main \
--head sync/upstream \
--title "chore: sync upstream doocs/md" \
--body "$BODY"
fi
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,16 @@ dev-dist
# uTools build artifacts
apps/utools/dist
apps/utools/release

# Corepack cache, relocated inside the workspace when the home cache is not writable
.corepack

# Playwright browser cache relocated inside the workspace when the home cache is not writable
.playwright-browsers

# implement-spec worktrees
.wt-ticket-*
.pnpm-store/

# local scratch docs (handoff notes, keep out of git)
temp/
Loading
Loading