@drawbridge/drawbridge-agents 0.1.74 → 0.1.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -23,8 +23,9 @@ bulleted section beside it. In order:
|
|
|
23
23
|
1. What changed, in plain past tense. Numbered.
|
|
24
24
|
2. What they need before the first step: a permission to grant, a setting to switch on, a
|
|
25
25
|
record that has to exist. One item each.
|
|
26
|
-
3. What to do and what to expect. One step per item,
|
|
27
|
-
|
|
26
|
+
3. What to do and what to expect. One step per item, one action per step (rules.md rule 9),
|
|
27
|
+
each one something they can actually do or check. "Open the campaign and click Draw" is
|
|
28
|
+
two steps. Every step starts with the click path from where they already are (Admin,
|
|
28
29
|
Connections, then the store; Shopify admin, Apps, then Drawbridge). "Open the app" is not a
|
|
29
30
|
path.
|
|
30
31
|
4. Anything that would otherwise look wrong to them. Numbered too.
|
|
@@ -7,7 +7,7 @@ Branches use the **full gitflow prefixes, always spelled out**. Never use abbrev
|
|
|
7
7
|
| `feature/<name>` | New features / changes (branched from `develop`) |
|
|
8
8
|
| `bugfix/<name>` | Non-urgent bug fixes |
|
|
9
9
|
| `hotfix/<name>` | Urgent production fixes (branched from `main`) |
|
|
10
|
-
| `release/<
|
|
10
|
+
| `release/<asana id>` | A release (since 2026-10-21): the Releases project task id, the same id as `drawbridge-api/scripts/migration-<id>.js` and `drawbridge-docs/releases/<id>.md`; one branch per app the release touches, off `develop`, built against the Local database, merged by a developer through a pull request |
|
|
11
11
|
| `chore/<name>` | Maintenance — dependency bumps, config, cleanup |
|
|
12
12
|
| `support/<name>` | Long-lived support branches |
|
|
13
13
|
|
|
@@ -29,11 +29,50 @@ quietly that dev served stale code the whole time.
|
|
|
29
29
|
|
|
30
30
|
## How
|
|
31
31
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
32
|
+
- One release has at most one migration file,
|
|
33
|
+
`drawbridge-api/scripts/migration-<release asana id>.js`, named for the
|
|
34
|
+
RELEASE task (the same id as the `release/<id>` branches and
|
|
35
|
+
`drawbridge-docs/releases/<id>.md`), holding every data step the release
|
|
36
|
+
needs and exporting
|
|
37
|
+
`({ controller }) => async ({ dryRun, organization, ...args }) => counts`.
|
|
38
|
+
Nothing at boot requires `scripts/`; `test/migrations-folder.test.js` refuses
|
|
39
|
+
any other file there. **The folder only ever holds what production has not
|
|
40
|
+
run**: once the production run is recorded, `git rm` the file (the promote
|
|
41
|
+
step will do this), so two releases in flight are two files and no spent code
|
|
42
|
+
lingers. (Until 2026-10-21 these were functions in one
|
|
43
|
+
`scripts.js` that boot required and that kept its fifteen spent functions for
|
|
44
|
+
a month; Darren, 2026-10-21: "avoids old code kicking around".)
|
|
45
|
+
- Take `{ dryRun, organization }` and report what it would do as the object you
|
|
46
|
+
return (`{ found, updated }` or whatever the counts are). The first run of a
|
|
47
|
+
migration is a read.
|
|
48
|
+
- Run it only through the runner. On a laptop, from the api checkout:
|
|
49
|
+
`npm run migrate -- <asana id> --dry --env dev`, then
|
|
50
|
+
`--organization <id> --env dev --release <slug>`, then `--env dev --release <slug>`.
|
|
51
|
+
No env file holds a value: the runner re-runs itself through `scripts/op.sh`
|
|
52
|
+
with the file `--env` names (`.env.local` / `.env.development`, two lines naming
|
|
53
|
+
a 1Password Environment), so the Environment is injected the way the servers
|
|
54
|
+
get it. It refuses the wrong cluster, hands a dry run a controller that throws
|
|
55
|
+
on any write, and writes the result to `runs/<env>-<fn>-<time>.json` (read the
|
|
56
|
+
file, never the console: `op run` conceals anything that looks like a secret).
|
|
57
|
+
- **Production runs inside the deployed api container**, never from a laptop,
|
|
58
|
+
so no laptop ever holds a production file: `doctl apps console <prod api app
|
|
59
|
+
id> drawbridge-api`, then `op run --environment "$OP_ENVIRONMENT_ID" -- node
|
|
60
|
+
migrate.js <asana id> --env prod --dry --sha <promoted commit>`, then the same
|
|
61
|
+
without `--dry` and with `--release <slug>`. The image carries `migrate.js`
|
|
62
|
+
and `scripts/`. There is no git there, so the runner proves `--sha`
|
|
63
|
+
against `APP_COMMIT_HASH` (the deployed commit, injected by the app spec); in
|
|
64
|
+
a checkout it still refuses production off `main`, at the wrong commit, or with
|
|
65
|
+
`scripts/`, `lib/` or `migrate.js` modified. `cat` the counts file from the
|
|
66
|
+
console shell afterwards, outside `op run`, to read it unconcealed.
|
|
67
|
+
- A real fleet run records itself when drawbridge-docs sits beside the api:
|
|
68
|
+
`drawbridge-docs/releases/<slug>.json` gets
|
|
69
|
+
`migrations.<asana id>.<development|production> = true`, and the release
|
|
70
|
+
document `releases/<slug>.md` gets a row in its Migrations table. That is how
|
|
71
|
+
"has it run on prod?" is answered. In the container there is no docs checkout:
|
|
72
|
+
the runner prints exactly which flag and row to write, and you commit them
|
|
73
|
+
from a laptop from the counts file. After a production run the promote step
|
|
74
|
+
deletes `scripts/migration-<asana id>.js`, so the folder only ever holds what
|
|
75
|
+
has not run.
|
|
37
76
|
- Add it to the release document in `drawbridge-docs/releases/` for the launch it
|
|
38
77
|
belongs to, with the ordering constraint stated: what has to be deployed before
|
|
39
78
|
it can run, and what breaks if it runs early.
|
package/conventions/rules.md
CHANGED
|
@@ -36,3 +36,7 @@
|
|
|
36
36
|
8. Never make it up. A statement of fact in anything you write to a person is backed by something you read in this session: a file you opened whole, a doc in `drawbridge-docs`, the knowledge graph, a vendor's documentation you fetched, a value you measured. If none of those backs it, it is not a fact yet: say "I do not know" or put it to Darren as a numbered question. Never write a step in the past tense for something you have not done ("Updated the step in the task" when nothing was edited). Never describe a thing as absent because you have not found it yet; rule 6 says how to search first.
|
|
37
37
|
|
|
38
38
|
Why: a confident sentence with nothing behind it reads exactly like a verified one, and the reader builds on it. It has sent a tester hunting for a badge that did not exist, described a repo as missing code that was in another package, and promised an edit that had not happened. Every one of those was cheaper to ask about than to correct afterwards.
|
|
39
|
+
|
|
40
|
+
9. Write in the spirit of ASD-STE100. One idea per sentence, with an active verb, in about 20 words. A procedural step is one action: "Open the campaign. Click Draw." never "Open the campaign and click Draw". A condition or warning comes before the step it applies to, never after. One word has one meaning for the whole reply: do not swap in synonyms for variety, and write "must" for a requirement and "we recommend" for advice, never "should". The STE dictionary is not in force; use the words the team uses (rule 7).
|
|
41
|
+
|
|
42
|
+
Why: STE exists so that a reader who skims under pressure cannot misread a step. That is Jaime reading a retest list and Darren reading a question. Darren, 2026-10-21, asked for the spirit of STE and not the letter.
|
package/package.json
CHANGED
package/scripts/check-stories.js
CHANGED
|
@@ -35,7 +35,7 @@ const UNDO = [
|
|
|
35
35
|
[ /\bpublish(es|ed|ing)?\b/i, /\bunpublish/i, 'publish', 'unpublish' ],
|
|
36
36
|
[ /\bpaus(e|es|ed|ing)\b/i, /\bresum(e|es|ed|ing)\b/i, 'pause', 'resume' ],
|
|
37
37
|
[ /\benabl(e|es|ed|ing)\b/i, /\bdisabl(e|es|ed|ing)\b/i, 'enable', 'disable' ],
|
|
38
|
-
[ /\barchiv(e|es|ed|ing)\b/i, /\b(unarchiv|restor)/i, 'archive', 'restore' ]
|
|
38
|
+
[ /\barchiv(e|es|ed|ing)\b|\bwrit(e|es|ing)\s+(it\s+)?off\b/i, /\b(unarchiv|restor)/i, 'archive or write off', 'restore' ]
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
const findFamilyRoot = () => {
|