Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4c93e10
docs(i18n): translate the entry path into ja (index, why, start, edit…
zhuangjianguo Oct 29, 2026
408661e
docs(i18n): translate build/ and build/data/ into ja (#388, PR 1 of 7)
zhuangjianguo Oct 29, 2026
e897011
Merge the merged #387 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
9613e53
Merge main (#389 landed) so the push fast-forwards
zhuangjianguo Oct 29, 2026
38384aa
docs(i18n): translate build/automation/ and build/interface/ into ja …
zhuangjianguo Oct 29, 2026
577b635
fix(search): keep one locale index and read search text from build ou…
zhuangjianguo Oct 29, 2026
6434c3f
Merge the landed #390 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
d0ad718
docs(i18n): re-land build/automation/ and build/interface/ ja pages (…
zhuangjianguo Oct 29, 2026
ace646b
Merge the landed #394 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
3fd7047
fix(worker): stop bundling every docs page twice (#395)
zhuangjianguo Oct 29, 2026
6769cd3
Merge the landed #396 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
fadc71d
Merge the landed #397 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
8688a48
docs(i18n): translate configure/ into ja (#388, PR 3 of 7)
zhuangjianguo Oct 29, 2026
c881844
Merge the landed #398 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
8fdcd28
docs(i18n): translate configure/permissions/ and cloud/ into ja (#388…
zhuangjianguo Oct 29, 2026
216f90a
Merge the landed #399 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
c74c76a
docs(i18n): translate deploy/ and operate/ into ja (#388, PR 5 of 7)
zhuangjianguo Oct 29, 2026
2a5fa2b
Merge the landed #400 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
3df88d4
docs(i18n): translate reference/, architecture and ontology into ja (…
zhuangjianguo Oct 29, 2026
41256ca
Merge the landed #401 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
4b48d10
docs(i18n): translate resources/ into ja, completing ja coverage (#38…
zhuangjianguo Oct 29, 2026
f431ff5
Merge the landed #402 branch head so the push fast-forwards
zhuangjianguo Oct 29, 2026
84a7d23
docs(i18n): re-sync start/cloud step 1 in zh-Hans, zh-Hant and ja (#404)
zhuangjianguo Oct 29, 2026
a20706a
Merge the landed #405 branch head so the push fast-forwards
zhuangjianguo Oct 31, 2026
470446b
docs(i18n): re-sync six pages changed by #410 and #413 in zh-Hans, zh…
zhuangjianguo Oct 31, 2026
26b6ca0
Merge the landed #415 branch head so the push fast-forwards
zhuangjianguo Nov 1, 2026
08e409e
docs(positioning): quote the README's three-edition sentence (#341)
zhuangjianguo Nov 1, 2026
50b0683
Merge the landed #416 branch head so the push fast-forwards
zhuangjianguo Nov 2, 2026
cfe6ce3
docs(i18n): re-sync editions/compare and editions/license after #407 …
zhuangjianguo Nov 2, 2026
6809541
Merge the landed #419 branch head so the push fast-forwards
zhuangjianguo Nov 2, 2026
4cdb438
docs(architecture): ObjectOS layer row in three-edition terms (#417)
zhuangjianguo Nov 2, 2026
b4bb660
Merge the landed #420 branch head so the push fast-forwards
zhuangjianguo Nov 2, 2026
9abc331
docs(templates): remove the five retired templates from the catalog a…
zhuangjianguo Nov 2, 2026
1d3afa4
Merge the landed #422 branch head so the push fast-forwards
zhuangjianguo Nov 2, 2026
63f5c81
docs(upgrade): JWT key rotation follows the deployment's own procedur…
zhuangjianguo Nov 2, 2026
23375c4
docs(positioning): exporting a Cloud or Enterprise ontology to the op…
zhuangjianguo Nov 2, 2026
09e9078
Merge the landed #423 branch head so the push fast-forwards
zhuangjianguo Nov 2, 2026
48ec6c0
docs(i18n): translate six cloud and editions pages after one environm…
zhuangjianguo Nov 3, 2026
57a5be4
Merge main 0c3fe8f (#431) into the #429 branch
zhuangjianguo Nov 3, 2026
9c5ec99
Merge the landed #425 branch head so the push fast-forwards
zhuangjianguo Nov 3, 2026
c836d59
docs(i18n): follow #431 plan B in zh-Hans, zh-Hant and ja; translate …
zhuangjianguo Nov 3, 2026
4185047
chore(upstream): the cloud pin moves by hand; the bump workflow moves…
zhuangjianguo Nov 3, 2026
f29c119
Merge the landed #429 branch head so the push fast-forwards
zhuangjianguo Nov 3, 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
73 changes: 51 additions & 22 deletions .github/scripts/bump-upstream-pin.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env node
/**
* Upstream pins — move one of `.objectstack-sha` / `.cloud-sha` and write the
* pull-request body that lists what changed upstream since the previous pin.
* Upstream pins — check both `.objectstack-sha` and `.cloud-sha`, and move the
* objectstack pin, writing the pull-request body that lists what changed
* upstream since the previous pin. The cloud pin is moved by hand (below).
*
* ## Why this exists
*
Expand All @@ -12,27 +13,38 @@
* pass misses. A pin turns it into a bounded one: each file at the repository
* root holds the one upstream commit the site was last aligned to, and every
* alignment is a review of the upstream commits and changed paths since that
* commit. This script computes that range; `bump-upstream-docs.yml` runs it
* and opens the pull request whose body it writes.
* commit. For objectstack this script computes that range;
* `bump-upstream-docs.yml` runs it and opens the pull request whose body it
* writes.
*
* ## When a pin moves
*
* objectstack on a published `@objectstack/cli` release — the commit its
* release tag `@objectstack/cli@VERSION` names. With no `--sha`,
* the release is npm's `latest` dist-tag.
* cloud after a successful cloud production deploy — the commit that
* deploy serves, never a merge to cloud's `main`. There is no
* default: the deploy supplies `--sha`, and the run refuses
* without one.
* the release is npm's `latest` dist-tag. This script moves it.
* cloud BY HAND, when someone refreshes the docs to match production —
* not on every cloud release (maintainer ruling,
* docs.objectos.ai#433). The person writes the full SHA of the
* commit production serves (cloud's `v*` tag, or its
* deploy-cloud-prod run; the health header's 8-character
* `x-objectstack-build-sha` only identifies it) and pastes
* `git log OLD..NEW -- CHANGELOG.md .changeset/` from a local
* cloud checkout into the pull-request body. No workflow, dispatch
* or token moves it, and this script refuses `--upstream cloud`:
* cloud is private and this repository holds no token to read it.
* AGENTS.md "Upstream pins" has the steps.
*
* `--check` validates both pin files the same way, by format alone; it reads
* neither upstream, so a hand-edited `.cloud-sha` passes it like any other.
*
* ## The pin file
*
* Exactly one line: a full, lowercase, 40-character commit SHA. The one other
* accepted value is the placeholder `unpinned`, for an upstream that has never
* been pinned (`.cloud-sha` ships with it, because cloud is a private
* repository this site's maintainers could not read when the pins were added).
* A range cannot start at the placeholder, so the first bump of an unpinned
* upstream only records the commit and says so; the next bump is the first
* A range cannot start at the placeholder, so the first move of an unpinned
* pin only records the commit and lists nothing; the next one is the first
* bounded diff. A missing file, an empty one, an abbreviated SHA or a branch
* name is refused — a pin that cannot be resolved to one commit bounds nothing.
*
Expand All @@ -41,8 +53,8 @@
* - the new commit is not a descendant of the current pin — the range
* `OLD..NEW` would silently drop whatever `OLD` has that `NEW` lacks, and
* the review would read a diff that is not the change;
* - the upstream cannot be read — cloud is private and needs `UPSTREAM_TOKEN`;
* - a cloud bump with no `--sha`.
* - the upstream cannot be read;
* - a bump of an upstream whose pin is moved by hand (cloud).
*
* A bump to the commit already pinned is not an error: it writes nothing,
* reports `changed=false`, and the workflow opens no pull request.
Expand All @@ -62,7 +74,7 @@
*
* node .github/scripts/bump-upstream-pin.mjs --check
* Validate both pin files. Exit 1 naming each bad one.
* node .github/scripts/bump-upstream-pin.mjs --upstream objectstack|cloud \
* node .github/scripts/bump-upstream-pin.mjs --upstream objectstack \
* [--sha SHA] --body FILE [--git-dir DIR]
* Resolve, fetch (blobless) into DIR, write the new pin and the body.
* Writes `changed`, `old`, `new`, `short`, `label` and `title` to $GITHUB_OUTPUT
Expand All @@ -79,19 +91,25 @@ import { spawnSync } from 'node:child_process';

const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');

/** The two upstreams. `paths` is what the alignment review reads. */
/**
* The two upstreams. `paths` is what the alignment review reads. `byHand` marks
* a pin this script checks but never moves (docs.objectos.ai#433): its paths are
* the ones the person moving it lists with `git log` in the pull-request body.
*/
const UPSTREAMS = {
objectstack: {
repo: 'objectstack-ai/objectstack',
pinFile: '.objectstack-sha',
paths: ['content/docs', 'docs/releases', 'CHANGELOG.md'],
release: '@objectstack/cli',
byHand: false,
},
cloud: {
repo: 'objectstack-ai/cloud',
pinFile: '.cloud-sha',
paths: ['CHANGELOG.md', '.changeset'],
release: null,
byHand: true,
},
};

Expand Down Expand Up @@ -124,6 +142,17 @@ function parseUpstream(name) {
return UPSTREAMS[name];
}

/** An upstream this script may move: declared, and not moved by hand. */
function bumpable(name) {
const up = parseUpstream(name);
if (up.byHand) {
throw new Refusal(
`${up.pinFile} is moved by hand, not by this script (docs.objectos.ai#433): write the full SHA production serves and paste \`git log OLD..NEW -- ${up.paths.join(' ')}\` from a local checkout into the pull-request body — see AGENTS.md "Upstream pins"`,
);
}
return up;
}

/** A `--sha` / dispatch-payload value: absent, or a full SHA. Never a ref name. */
function parseShaInput(value) {
const v = (value ?? '').trim();
Expand Down Expand Up @@ -265,7 +294,7 @@ function readPinFile(root, up) {

async function bump(opts) {
const name = opts.upstream;
const up = parseUpstream(name);
const up = bumpable(name);
const oldPin = readPinFile(opts.root, up);
const url = `https://github.com/${up.repo}.git`;
const env = gitEnv(process.env.UPSTREAM_TOKEN);
Expand All @@ -274,9 +303,6 @@ async function bump(opts) {
let source = 'supplied by the run that requested this bump';
let target = null;
if (!newSha) {
if (!up.release) {
throw new Refusal(`a ${name} bump needs --sha: the commit its production deploy serves (there is no default)`);
}
const version = await latestRelease(up.release);
const tag = `${up.release}@${version}`;
const ls = git(['ls-remote', url, `refs/tags/${tag}`, `refs/tags/${tag}^{}`], { env });
Expand All @@ -294,8 +320,7 @@ async function bump(opts) {
const wants = kind === 'range' ? [newSha, oldPin.sha] : [newSha];
const fetched = git(['fetch', '--quiet', '--filter=blob:none', url, ...wants], { gitDir, env, allowFail: true });
if (fetched.status !== 0) {
const hint = name === 'cloud' && !process.env.UPSTREAM_TOKEN ? ' — cloud is private: set UPSTREAM_TOKEN' : '';
throw new Refusal(`could not fetch ${up.repo} at ${wants.join(', ')}${hint}: ${(fetched.stderr || '').trim().split('\n').pop()}`);
throw new Refusal(`could not fetch ${up.repo} at ${wants.join(', ')}: ${(fetched.stderr || '').trim().split('\n').pop()}`);
}
git(['cat-file', '-e', `${newSha}^{commit}`], { gitDir });

Expand Down Expand Up @@ -433,6 +458,10 @@ function selfTest() {
for (const bad of ['', 'objectui', 'toString', '__proto__', undefined]) {
expectRefusal(`upstream: ${JSON.stringify(bad)}`, () => parseUpstream(bad), 'unknown upstream');
}
// Only objectstack is bumped here; the cloud pin is moved by hand (#433), and the refusal says how.
if (bumpable('objectstack') !== UPSTREAMS.objectstack) fail('bump: objectstack is not bumpable');
expectRefusal('bump: cloud', () => bumpable('cloud'), 'moved by hand');
expectRefusal('bump: cloud names the git log to paste', () => bumpable('cloud'), 'git log OLD..NEW -- CHANGELOG.md .changeset');

// The pin a missing file refuses is the real reader, against a real (temporary) tree.
const empty = mkdtempSync(join(tmpdir(), 'pin-selftest-'));
Expand Down Expand Up @@ -489,7 +518,7 @@ function selfTest() {
process.exitCode = 1;
return;
}
console.log(`✓ self-test: ${total} pin/input case(s), upstream names, tag resolution, plan, body bounds and token carriage`);
console.log(`✓ self-test: ${total} pin/input case(s), upstream names, the hand-moved cloud pin, tag resolution, plan, body bounds and token carriage`);
}

/* ------------------------------------------------------------------ main -- */
Expand Down
50 changes: 25 additions & 25 deletions .github/workflows/bump-upstream-docs.yml
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
name: Bump upstream docs pin

# Moves ONE upstream pin — `.objectstack-sha` or `.cloud-sha` — and opens a
# pull request whose body lists the upstream commits and changed paths since
# the previous pin. That body is the alignment review's input: the site is
# checked against a bounded diff instead of a periodic re-read of both corpora.
# The rules for when each pin moves, and what the body lists, are in the header
# of `.github/scripts/bump-upstream-pin.mjs`; AGENTS.md has the short form.
# Moves the objectstack pin, `.objectstack-sha`, and opens a pull request whose
# body lists the upstream commits and changed paths since the previous pin.
# That body is the alignment review's input: the site is checked against a
# bounded diff instead of a periodic re-read of the corpus. The rules are in the
# header of `.github/scripts/bump-upstream-pin.mjs`; AGENTS.md has the short form.
#
# objectstack on a published `@objectstack/cli` release. With no `sha`, the
# run pins the commit tagged with npm's `latest` release.
# cloud after a successful cloud production deploy, to the commit that
# deploy serves. `sha` is required; the run refuses without it.
#
# The cloud pin, `.cloud-sha`, is NOT moved here: it is moved by hand when the
# docs are refreshed to match production (maintainer ruling,
# docs.objectos.ai#433), and the helper refuses `upstream: cloud`. AGENTS.md
# "Upstream pins" has the steps. This workflow still checks its format.
#
# Triggers: `workflow_dispatch` by hand, or `repository_dispatch` of type
# `bump-upstream-docs` with `client_payload: { upstream, sha }` — the shape a
# deploy or release workflow elsewhere sends. On a pull request that touches the
# pins, the helper or this file, the `pins` job runs the helper's self-test and
# checks both pin files.
# `bump-upstream-docs` with `client_payload: { upstream: objectstack, sha }` —
# the shape a release workflow elsewhere sends. On a pull request that touches
# the pins, the helper or this file, the `pins` job runs the helper's self-test
# and checks both pin files by format alone; it reads neither upstream.
#
# ⛔ One secret, `UPSTREAM_BUMP_TOKEN`, and the bump refuses to start without
# it. It is used for two things `GITHUB_TOKEN` cannot do here:
# - read `objectstack-ai/cloud`, a private repository (contents: read there);
# - push the bump branch and open the pull request (contents: write and
# pull-requests: write here). A pull request opened with `GITHUB_TOKEN`
# starts no `pull_request` workflows — GitHub suppresses them to prevent
# recursive runs — so CI would never run on the bump, and whether this
# repository lets Actions open pull requests at all is a repository setting.
# it. It pushes the bump branch and opens the pull request (contents: write and
# pull-requests: write here), which `GITHUB_TOKEN` cannot do usefully: a pull
# request it opens starts no `pull_request` workflows — GitHub suppresses them
# to prevent recursive runs — so CI would never run on the bump, and whether
# this repository lets Actions open pull requests at all is a repository
# setting.

on:
workflow_dispatch:
inputs:
upstream:
description: Which pin to move
description: Which pin to move (the cloud pin is moved by hand, see AGENTS.md)
type: choice
options: [objectstack, cloud]
options: [objectstack]
required: true
sha:
description: >-
Full 40-character commit SHA to pin. Required for cloud (the commit its
production deploy serves). Leave empty for objectstack to pin npm's
latest @objectstack/cli release.
Full 40-character commit SHA to pin. Leave empty to pin npm's latest
@objectstack/cli release.
type: string
required: false
repository_dispatch:
Expand Down Expand Up @@ -96,7 +96,7 @@ jobs:
UPSTREAM_BUMP_TOKEN: ${{ secrets.UPSTREAM_BUMP_TOKEN }}
run: |
if [ -z "$UPSTREAM_BUMP_TOKEN" ]; then
echo "::error title=NOT CONFIGURED::The repository secret UPSTREAM_BUMP_TOKEN is not set. It needs contents: read on objectstack-ai/cloud and contents: write + pull-requests: write on this repository. GITHUB_TOKEN is not a substitute: it cannot read cloud, and a pull request it opens runs no CI."
echo "::error title=NOT CONFIGURED::The repository secret UPSTREAM_BUMP_TOKEN is not set. It needs contents: write + pull-requests: write on this repository. GITHUB_TOKEN is not a substitute: a pull request it opens runs no CI. (The cloud pin needs no token: it is moved by hand, see AGENTS.md.)"
exit 1
fi

Expand Down
12 changes: 11 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,17 @@ node .github/scripts/check-translations.mjs --worklist # what the next pass wil

## Upstream pins

`.objectstack-sha` and `.cloud-sha` at the repository root each hold one full commit SHA: the commit of `objectstack-ai/objectstack` and of `objectstack-ai/cloud` this site was last aligned to. The objectstack pin moves when an `@objectstack/cli` release is published, to the commit its release tag names; the cloud pin moves after a successful cloud production deploy, to the commit that deploy serves — never on a merge to cloud's `main`. ⛔ Don't edit a pin by hand: `.github/workflows/bump-upstream-docs.yml` (run by hand, or a `repository_dispatch` of type `bump-upstream-docs` with `{ upstream, sha }`) moves one pin and opens a PR whose body lists the upstream commits and changed paths since the previous pin — objectstack: `content/docs`, `docs/releases`, `CHANGELOG.md`; cloud: `CHANGELOG.md`, `.changeset/`. That list is the alignment review's input: update the English pages it affects before the pin lands. `.cloud-sha` holds the placeholder `unpinned` until its first bump, which records a commit and lists nothing. The rules live in the header of `.github/scripts/bump-upstream-pin.mjs`.
`.objectstack-sha` and `.cloud-sha` at the repository root each hold one full commit SHA: the commit of `objectstack-ai/objectstack` and of `objectstack-ai/cloud` this site was last aligned to. What changed upstream between the old pin and the new one is the alignment review's input: update the English pages it affects before the pin lands.

**The objectstack pin** moves when an `@objectstack/cli` release is published, to the commit its release tag names. ⛔ Don't edit it by hand: `.github/workflows/bump-upstream-docs.yml` (run by hand, or a `repository_dispatch` of type `bump-upstream-docs` with `{ upstream: "objectstack", sha }`) moves it and opens a PR whose body lists the upstream commits and changed paths since the previous pin in `content/docs`, `docs/releases` and `CHANGELOG.md`. Opening that PR needs the repository secret `UPSTREAM_BUMP_TOKEN`.

**The cloud pin moves by hand** (maintainer ruling, #433): when someone refreshes the docs to match production, not on every cloud release. No workflow, dispatch or token moves it. To move it:

1. Take the full 40-character SHA of the commit production serves: `git rev-parse vX.Y.Z^{commit}` on cloud's `v*` release tag, or the commit of cloud's `deploy-cloud-prod` run. The `x-objectstack-build-sha` header of `https://cloud.objectos.ai/api/v1/health` has only the first 8 characters: it tells you which commit, but it is not a pin.
2. Write that SHA to `.cloud-sha` as the file's only line.
3. In the PR body, paste the output of `git log <old>..<new> -- CHANGELOG.md .changeset/`, run in a local cloud checkout. That list is the alignment review's input. The first hand update, from the placeholder `unpinned`, has no previous commit, so it lists nothing.

On a PR that touches a pin, the `pins` job checks the format only (a full lowercase SHA, or `unpinned`) and reads neither upstream. The rules live in the header of `.github/scripts/bump-upstream-pin.mjs`.

## Commands

Expand Down
Loading