@agentsfleet/orly 0.9.4 → 0.10.1

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.
package/AGENTS.md CHANGED
@@ -144,7 +144,7 @@ Guards fire pre-hoc regardless of lifecycle stage. Override: `<GATE>: SKIPPED pe
144
144
  | write auth-flow / token-minting files | `write_auth` | `dispatch/write_auth.md` — auth invariants; reads the product repo's `docs/AUTH.md` before · 🟣 delegated (product repo). |
145
145
  | write published docs / OpenAPI prose | `write_documentation` | `dispatch/write_documentation.md` → `docs/DOCUMENTATION_RULES.md` before narrower guides; page, fragment, API, changelog scopes differ · 🟣 delegated to repository pre-commit checks. |
146
146
  | write a changelog entry | `write_changelog` | `dispatch/write_changelog.md` — changelog voice (one headline, no marketing words, `**Bold lead-noun**` bullets, history append-only); reads `docs/CHANGELOG_VOICE.md` · 🤔 judgment-only. |
147
- | write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; review dispositions; commands with real output. |
147
+ | write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; visual evidence from the lane's own artifacts; review dispositions; commands with real output. |
148
148
  | claim "tests pass / ready / shipping" | `verify` | `dispatch/verify.md` — verification tiers (`make` canonical; package-scoped runners are **not** verification), done-message glyph format · 🤔 judgment-only, `VERIFY GATE: <target> skipped per environment constraint (reason: ...)` only when genuinely unrunnable. |
149
149
  | name a stream/channel/Redis namespace/queue/RPC/Postgres schema, or describe a flow | `name_architecture` | `dispatch/name_architecture.md` — architecture-consult discipline; grep relevant `docs/architecture/` (chat brainstorming counts) · **no override** — doc wins until reconciled. |
150
150
  | run a lifecycle stage (open→close a stream, worktree setup, milestone bootstrap) | `lifecycle` | `dispatch/lifecycle.md` — stage runbooks: CHORE(open/close) checklists, PLAN expansions, spec discipline, deferral format, pre-PR gates, LAND · 🤔 judgment-only. |
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
- # design-tokens.sh — enforce design-system token discipline across
3
- # ui/packages/{app,website}/**/*.tsx.
2
+ # design-tokens.sh — enforce design-system token discipline and flat fills
3
+ # across the app, website, and shared design system.
4
4
  #
5
5
  # Dispatch façade: dispatch/write_ts_adhere_bun.md (Design Tokens / DESIGN TOKEN GATE)
6
6
  # Fires in: CONFORM (via `make harness-verify` in `agentsfleet`).
@@ -62,6 +62,23 @@ PATTERNS=(
62
62
  '(text|bg|border)-(red|blue|green|yellow|purple|indigo|violet|pink|orange|gray|slate|zinc|neutral)-[0-9]:::use semantic tokens (text-destructive, text-error, text-success, …)'
63
63
  )
64
64
 
65
+ readonly GRADIENT_REGEX='(repeating-)?(linear|radial|conic)-gradient[[:space:]]*\('
66
+
67
+ # Consumers may select a font role, but only the design system defines it.
68
+ check_font_ownership() {
69
+ local f="$1"
70
+ case "$f" in ui/packages/design-system/*) return ;; esac
71
+ awk '
72
+ {
73
+ source = $0
74
+ gsub(/font-family[[:space:]]*:[[:space:]]*var\(--ff-(sans|mono|display)\)/, "")
75
+ invalid = /font-family[[:space:]]*:|fontFamily[[:space:]]*:[[:space:]]*["\047]|--(ff|font)-(sans|mono|display)[[:space:]]*:|font-\[/
76
+ if (FILENAME ~ /^ui\/packages\/app\// && /font-display|DisplayXL|DisplayLG/) invalid = 1
77
+ if (invalid) printf "%s:%d:%s\n", FILENAME, FNR, source
78
+ }
79
+ ' "$f"
80
+ }
81
+
65
82
  # ── File scope ───────────────────────────────────────────────────────────
66
83
  in_scope() {
67
84
  local f="$1"
@@ -70,8 +87,17 @@ in_scope() {
70
87
  *tests/e2e/*) return 1 ;;
71
88
  ui/packages/app/*.tsx|ui/packages/app/*.jsx) return 0 ;;
72
89
  ui/packages/website/*.tsx|ui/packages/website/*.jsx) return 0 ;;
73
- ui/packages/app/**/*.tsx|ui/packages/app/**/*.jsx) return 0 ;;
74
- ui/packages/website/**/*.tsx|ui/packages/website/**/*.jsx) return 0 ;;
90
+ *) return 1 ;;
91
+ esac
92
+ }
93
+
94
+ in_gradient_scope() {
95
+ local f="$1"
96
+ case "$f" in
97
+ *.test.*|*.spec.*|*/tests/*|*/coverage/*|*/dist/*|*/.next/*|*/node_modules/*) return 1 ;;
98
+ ui/packages/app/*.css|ui/packages/app/*.js|ui/packages/app/*.jsx|ui/packages/app/*.mjs|ui/packages/app/*.ts|ui/packages/app/*.tsx) return 0 ;;
99
+ ui/packages/website/*.css|ui/packages/website/*.js|ui/packages/website/*.jsx|ui/packages/website/*.mjs|ui/packages/website/*.ts|ui/packages/website/*.tsx) return 0 ;;
100
+ ui/packages/design-system/*.css|ui/packages/design-system/*.js|ui/packages/design-system/*.jsx|ui/packages/design-system/*.mjs|ui/packages/design-system/*.ts|ui/packages/design-system/*.tsx) return 0 ;;
75
101
  *) return 1 ;;
76
102
  esac
77
103
  }
@@ -79,12 +105,14 @@ in_scope() {
79
105
  case "$MODE" in
80
106
  --staged|staged)
81
107
  FILES=$(git diff --cached --name-only --diff-filter=ACMRT 2>/dev/null || true)
108
+ GRADIENT_CANDIDATES="$FILES"
82
109
  ;;
83
110
  --all|all)
84
111
  # `git ls-files` reports the index, which includes staged content —
85
112
  # so pre-commit-style invocations see staged-but-not-committed files
86
113
  # without needing a `--staged` flag.
87
114
  FILES=$(git ls-files -- 'ui/packages/app/*.tsx' 'ui/packages/app/*.jsx' 'ui/packages/website/*.tsx' 'ui/packages/website/*.jsx' 2>/dev/null || true)
115
+ GRADIENT_CANDIDATES=$(git ls-files -- ui/packages/app ui/packages/website ui/packages/design-system 2>/dev/null || true)
88
116
  ;;
89
117
  *)
90
118
  echo "usage: $0 [--all|--staged]" >&2
@@ -127,10 +155,34 @@ if [ "${#SCOPED_FILES[@]}" -gt 0 ]; then
127
155
  done
128
156
  fi
129
157
 
158
+ GRADIENT_FILES=()
159
+ while IFS= read -r f; do
160
+ [ -z "$f" ] && continue
161
+ [ ! -f "$f" ] && continue
162
+ in_gradient_scope "$f" || continue
163
+ GRADIENT_FILES+=("$f")
164
+ while IFS= read -r match; do
165
+ [ -z "$match" ] && continue
166
+ printf '%s\n -> define fonts in design-system tokens.css; use sans for app UI and mono for technical values\n' "$match"
167
+ SEEN_FILES_LIST="${SEEN_FILES_LIST}${f}"$'\n'
168
+ FAIL=1
169
+ done < <(check_font_ownership "$f")
170
+ done <<< "$GRADIENT_CANDIDATES"
171
+
172
+ if [ "${#GRADIENT_FILES[@]}" -gt 0 ]; then
173
+ while IFS= read -r match; do
174
+ [ -z "$match" ] && continue
175
+ f="${match%%:*}"
176
+ printf '%s\n -> use a solid design-system color token; gradients are forbidden\n' "$match"
177
+ SEEN_FILES_LIST="${SEEN_FILES_LIST}${f}"$'\n'
178
+ FAIL=1
179
+ done < <(grep -nHE "$GRADIENT_REGEX" "${GRADIENT_FILES[@]}" 2>/dev/null || true)
180
+ fi
181
+
130
182
  FILES_WITH_VIOLATIONS=$(printf '%s' "$SEEN_FILES_LIST" | sort -u | grep -c . || true)
131
183
 
132
184
  if [ "$FAIL" = "0" ]; then
133
- echo "OK: design-token discipline — no arbitraries that have a token equivalent (mode=$MODE)"
185
+ echo "OK: design-token discipline — named utilities and flat fills verified (mode=$MODE)"
134
186
  exit 0
135
187
  fi
136
188
 
@@ -148,7 +148,7 @@ Guards fire pre-hoc regardless of lifecycle stage. Override: `<GATE>: SKIPPED pe
148
148
  | write auth-flow / token-minting files | `write_auth` | `dispatch/write_auth.md` — auth invariants; reads the product repo's `docs/AUTH.md` before · 🟣 delegated (product repo). | <!-- oracle-packs:domain.auth -->
149
149
  | write published docs / OpenAPI prose | `write_documentation` | `dispatch/write_documentation.md` → `docs/DOCUMENTATION_RULES.md` before narrower guides; page, fragment, API, changelog scopes differ · 🟣 delegated to repository pre-commit checks. | <!-- oracle-packs:domain.documentation -->
150
150
  | write a changelog entry | `write_changelog` | `dispatch/write_changelog.md` — changelog voice (one headline, no marketing words, `**Bold lead-noun**` bullets, history append-only); reads `docs/CHANGELOG_VOICE.md` · 🤔 judgment-only. | <!-- oracle-packs:domain.changelog -->
151
- | write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; review dispositions; commands with real output. | <!-- oracle-packs:universal.authoring -->
151
+ | write/update a PR or MR body or its session notes | `write_pr_description` | `dispatch/write_pr_description.md` — append numbered `Session notes`, `Review`, and `Make`; measured fenced diagrams; visual evidence from the lane's own artifacts; review dispositions; commands with real output. | <!-- oracle-packs:universal.authoring -->
152
152
  | claim "tests pass / ready / shipping" | `verify` | `dispatch/verify.md` — verification tiers (`make` canonical; package-scoped runners are **not** verification), done-message glyph format · 🤔 judgment-only, `VERIFY GATE: <target> skipped per environment constraint (reason: ...)` only when genuinely unrunnable. | <!-- oracle-packs:product.agentsfleet -->
153
153
  | name a stream/channel/Redis namespace/queue/RPC/Postgres schema, or describe a flow | `name_architecture` | `dispatch/name_architecture.md` — architecture-consult discipline; grep relevant `docs/architecture/` (chat brainstorming counts) · **no override** — doc wins until reconciled. | <!-- oracle-packs:universal.authoring -->
154
154
  | run a lifecycle stage (open→close a stream, worktree setup, milestone bootstrap) | `lifecycle` | `dispatch/lifecycle.md` — stage runbooks: CHORE(open/close) checklists, PLAN expansions, spec discipline, deferral format, pre-PR gates, LAND · 🤔 judgment-only. |
@@ -40,8 +40,10 @@ a gate skip.
40
40
  names, money amounts stay verbatim.
41
41
  - **Internal cleanup** gets aggressive trimming, not a paragraph.
42
42
  - **History is archived, not rewritten** — past entries are an immutable record.
43
- - **Rate constants** stay pinned across the three files (`tenant_billing.zig`,
44
- `rates.ts`, `rates.mdx`) — a changelog money/rate claim must match all three.
43
+ - **Rate constants** are pinned by `cross_runtime_rates.rs`, which reads the
44
+ app and Command-Line Interface (CLI) mirrors against the Rust constant. A
45
+ changelog money or rate claim must match those, and `rates.mdx` in the docs
46
+ repository, which no test can reach.
45
47
 
46
48
  ## Required output (self-audit line before committing the changelog)
47
49
 
@@ -84,6 +84,37 @@ their numbers:
84
84
  0.003-0.005ms 0.1ms 1.0ms 12-21ms
85
85
  ```
86
86
 
87
+ ## Visual evidence
88
+
89
+ A change to a surface a person looks at, or a failure a picture explains faster
90
+ than a paragraph, carries the picture. A reviewer who can see the wall, the
91
+ dialog or the red run decides in seconds what a description makes them
92
+ reconstruct.
93
+
94
+ **Take it from what already ran, not from a staged pose.** A lane that failed
95
+ has already produced the image: `gh run download <id> -n <artifact>` yields
96
+ Playwright's `test-failed-*.png`, its `trace.zip` and its `error-context.md`.
97
+ Those are measured evidence of the state under review. A browser driven by hand
98
+ is the fallback, for a surface no lane photographs.
99
+
100
+ **Screenshot the claim, not the neighbourhood.** One image per assertion, and
101
+ the assertion named in the caption — "one tile, not two" beats "the fleets
102
+ page". Never crop a failure out of a frame that contained it.
103
+
104
+ **Attaching is the author's step, and say so rather than pretending.** No forge
105
+ accepts an image upload to a pull-request body over its command-line interface;
106
+ `gh` and `glab` both have no such call. So the agent hands the file to the
107
+ person and the person drags it in. What the agent MUST do in the body is make
108
+ the evidence retrievable without the image: name the run id, the artifact and
109
+ the path inside it, and quote the decisive line. A body that says
110
+ `error-context.md:27 records unexpected value "hidden"` survives a screenshot
111
+ nobody attached; a body that says "see screenshot" does not.
112
+
113
+ **A before/after belongs in a fence, not in two images**, when the difference is
114
+ countable — the diagram rules above already cover it, and a diagram diffs
115
+ better than a pair of pictures. Use images for what only rendering shows:
116
+ alignment, spacing, contrast, what a person actually sees.
117
+
87
118
  ## Review
88
119
 
89
120
  Lead with the review result. Record every finding with P0, P1, or P2 severity,
@@ -142,6 +173,11 @@ a green pipeline.
142
173
  <Useful measured diagram, at most 78 columns.>
143
174
  ```
144
175
 
176
+ <Visual evidence, when a surface changed or a picture explains a failure:
177
+ each image named with the assertion it carries and with the run, artifact and
178
+ path it came from, plus the decisive line quoted so the claim survives an
179
+ image nobody attached.>
180
+
145
181
  ## Review
146
182
 
147
183
  <P0/P1/P2 entries with dispositions, No findings., or not-run reason.>
@@ -14,5 +14,5 @@ Editing `~/Projects/docs/changelog.mdx` or any other Mintlify `<Update>` block.
14
14
  - **Internal cleanup / refactor entries get the most aggressive trimming.** One lead paragraph + one bullet list. Skip "Test coverage" sections unless the test count is the headline. Indy's exact direction: *"Keep internal code cleanup, refactor to a minimal."*
15
15
  - **Never drop load-bearing facts.** Error codes (`UZ-AUTH-003`), endpoint paths + method + body shape + status code, env var names + defaults, schema column / table names, CLI subcommand + flag names, migration steps, money amounts. Tighten prose, not meaning.
16
16
  - **Historical entries are archives.** Brevity-pass them; never rewrite the past. A typo correction (e.g. `$0.001` → `$0.01` when it was never true) is allowed and must be called out in the commit message.
17
- - **Rate constants flow through three pinned files only:** `rustd/crates/afd_billing/src/nanos.rs`, `ui/packages/website/src/lib/rates.ts`, `~/Projects/docs/snippets/rates.mdx`. Bumping a rate requires a paired Pull Request (PR) across the docs repo — there is no automated guard. In `*.mdx`, use `import { STARTER_CREDIT, EVENT_RATE, STAGE_RATE } from "/snippets/rates.mdx"` instead of hand-typing `$5`.
17
+ - **Rate constants stay pinned across the runtime surfaces, and a test says so.** `rustd/crates/afd_billing/tests/cross_runtime_rates.rs` reads `ui/packages/app/lib/types.ts` and `cli/src/constants/billing.ts` and fails when either drifts from `rustd/crates/afd_billing/src/nanos.rs` — a test beside the constant it defends, not a gate nothing invokes. Public docs are the one surface it cannot reach: when a rate changes, update `~/Projects/docs/snippets/rates.mdx` in a paired Pull Request (PR). In `*.mdx`, import its named values rather than hand-typing money amounts.
18
18
  - **The Mintlify reference Indy pasted (May 1 / May 8 entries) is canonical voice.** Mirror its rhythm, not its product nouns.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentsfleet/orly",
3
- "version": "0.9.4",
3
+ "version": "0.10.1",
4
4
  "description": "Repository-scoped engineering harness: renders agent rules, materialises the gates that enforce them, and proves the PR boundary \u2014 for any coding agent.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/registry.json CHANGED
@@ -296,10 +296,6 @@
296
296
  "product.agentsfleet": {
297
297
  "extensions": [],
298
298
  "managed_files": [
299
- {
300
- "source": "audits/cross-tier-rates.sh",
301
- "target": "audits/cross-tier-rates.sh"
302
- },
303
299
  {
304
300
  "source": "audits/design-tokens.sh",
305
301
  "target": "audits/design-tokens.sh"
@@ -1,105 +0,0 @@
1
- #!/usr/bin/env bash
2
- # cross-tier-rates.sh — pin numeric parity of the rate constants
3
- # across the daemon + three TypeScript surfaces.
4
- #
5
- # RULE UFS extension. The shipped billing surface depends on these constants
6
- # having identical numeric values everywhere they appear:
7
- #
8
- # RUN_NANOS_PER_SEC — per-second run rate (both postures) in nanos
9
- #
10
- # Two free-trial constants were pinned here and are both gone. FREE_TRIAL_END_MS
11
- # went when the boundary moved onto the tenant row; FREE_TRIAL_STAGE_NANOS went
12
- # when the trial mechanism was removed outright, because a rate that could
13
- # silently price a metered slice to zero was worth deleting rather than
14
- # guarding. The free allowance is wallet credit now — a balance, not a rate —
15
- # so there is no cross-tier number to pin for it.
16
- #
17
- # Files (one definition site per constant per file):
18
- #
19
- # rustd/crates/afd_billing/src/nanos.rs — server enforces the charge
20
- # ui/packages/website/src/lib/rates.ts — pricing page display
21
- # ui/packages/app/lib/types.ts — dashboard display
22
- # cli/src/constants/billing.ts — `agentsfleet doctor --json` billing block
23
- #
24
- # A drift between any two = a billing-display lie or a server-vs-CLI disagreement.
25
- # The daemon is the source of truth (server enforces); the three TS surfaces echo it.
26
- #
27
- # Fires in: make harness-verify, make harness-verify-all.
28
- # Exits 0 clean, 1 on any drift.
29
-
30
- set -euo pipefail
31
-
32
- ROOT="$(git rev-parse --show-toplevel)"
33
- cd "$ROOT"
34
-
35
- readonly NAMES=(
36
- RUN_NANOS_PER_SEC
37
- )
38
-
39
- readonly FILES=(
40
- rustd/crates/afd_billing/src/nanos.rs
41
- ui/packages/website/src/lib/rates.ts
42
- ui/packages/app/lib/types.ts
43
- cli/src/constants/billing.ts
44
- )
45
-
46
- # Extract the numeric value bound to `name` in `file`. Matches definition
47
- # sites only — `^(pub |export )?const NAME` — not usages elsewhere in the
48
- # file. Normalises: strips underscores (Zig `1_000_000`, TS `1_000_000`),
49
- # strips the bigint `n` suffix (TS `1_000_000n`), trims whitespace.
50
- extract_value() {
51
- local file="$1" name="$2"
52
- grep -E "^[[:space:]]*(pub |export )?const ${name}\\b" "$file" 2>/dev/null \
53
- | head -1 \
54
- | sed -E "s|.*=[[:space:]]*||; s|[;,].*||; s|//.*||; s|[[:space:]_n]||g"
55
- }
56
-
57
- FAIL=0
58
- violations=()
59
-
60
- printf "audit-cross-tier-rates: pinning %d constants across %d files\n" \
61
- "${#NAMES[@]}" "${#FILES[@]}"
62
-
63
- for name in "${NAMES[@]}"; do
64
- expected=""
65
- expected_file=""
66
- for file in "${FILES[@]}"; do
67
- if [[ ! -f "$file" ]]; then
68
- violations+=("MISSING_FILE: $file")
69
- FAIL=1
70
- continue
71
- fi
72
- val="$(extract_value "$file" "$name")"
73
- if [[ -z "$val" ]]; then
74
- violations+=("MISSING_CONST: $name not defined in $file")
75
- FAIL=1
76
- continue
77
- fi
78
- if [[ -z "$expected" ]]; then
79
- expected="$val"
80
- expected_file="$file"
81
- continue
82
- fi
83
- if [[ "$val" != "$expected" ]]; then
84
- violations+=("DRIFT: $name = $val in $file vs $expected in $expected_file")
85
- FAIL=1
86
- fi
87
- done
88
- if [[ -n "$expected" ]]; then
89
- printf " OK %-26s = %s\n" "$name" "$expected"
90
- fi
91
- done
92
-
93
- if [[ $FAIL -ne 0 ]]; then
94
- printf "\nFAIL: cross-tier rate drift detected:\n" >&2
95
- for v in "${violations[@]}"; do
96
- printf " %s\n" "$v" >&2
97
- done
98
- printf "\nFix: align all four files on the canonical Zig value\n" >&2
99
- printf " (rustd/crates/afd_billing/src/nanos.rs is the server-side enforcer).\n" >&2
100
- exit 1
101
- fi
102
-
103
- printf "OK: all %d rate constants pin across %d files\n" \
104
- "${#NAMES[@]}" "${#FILES[@]}"
105
- exit 0