154 lines
8.7 KiB
Markdown
154 lines
8.7 KiB
Markdown
<!-- Generated by ai-sync. Edit ai/rules/ instead. -->
|
|
|
|
# Concise Comments
|
|
|
|
Cap any single comment block at **two lines**. Most should be one.
|
|
|
|
- Default to writing no comment. Only add one when the WHY is non-obvious — a hidden constraint, a subtle invariant, a workaround for a specific bug, behavior that would surprise a reader.
|
|
- If you're tempted to write a third line, the comment is wrong: either delete it, or replace it with a clearer name / smaller function so the code explains itself.
|
|
- Don't restate WHAT the code does — well-named identifiers already do that.
|
|
- Don't reference the current task, fix, or callers ("used by X", "added for the Y flow", "handles the case from issue #123") — those belong in the PR description and rot as the codebase evolves.
|
|
- This applies to inline `//` comments AND JSDoc/docstring blocks. A JSDoc whose summary line + one detail line covers the WHY is fine; a four-line paragraph is not.
|
|
|
|
If something genuinely needs more explanation, link to a doc or a memory file rather than inlining a wall of text in source.
|
|
|
|
# Autumn Shared Utils
|
|
|
|
Before writing inline `.filter()`, `.find()`, `.some()`, boolean predicate, or `<src>To<dst>` transform logic over Autumn objects (`Price`, `Entitlement`, `FullCusProduct`, `FullCustomer`, `Feature`, etc.), **check `autumn/shared/utils/` for an existing helper.** Reaching for `array.filter(... === id)` directly is almost always a sign the utility was missed.
|
|
|
|
The package is organized resource-first, pattern-second. Within each `<resource>Utils/` folder:
|
|
|
|
- `classify*/` — `is*` boolean predicates (`isPrepaidPrice`, `isCustomerProductPaidRecurring`)
|
|
- `convert*/` — `<src>To<dst>` transforms (`cusProductToPrices`, `entToPrice`)
|
|
- `find*/` — `Array.find` lookups (`findFeatureById`, `findPriceByFeatureId`)
|
|
- `filter*/` — `Array.filter` collections (`filterCustomerProductsByFeatureId`)
|
|
- `enrich*` files — augment with joined data (`enrichEntitlementWithFeature`)
|
|
|
|
**If the helper you need doesn't exist, ALWAYS ask the user before adding one.** Naming and folder placement are cross-cutting and non-trivial — wrong placement clutters `@autumn/shared` for every consumer.
|
|
|
|
Full convention (folder tree, naming nuances, anti-patterns): see the `shared-utils` skill.
|
|
|
|
# Installing External Skills
|
|
|
|
Third-party skills installed via `bunx skills add <pkg>` land under each agent's local skill dir (`.claude/skills/`, `.cursor/skills/`, etc.). Those locations are NOT a source of truth — `bun ai sync` only reads from `ai/config/skills/**` and prunes anything else it manages, so a raw `bunx skills add` will not propagate to the other consumer repos (autumn, cloud).
|
|
|
|
## Workflow
|
|
|
|
1. Install via the CLI as usual:
|
|
```sh
|
|
bunx skills add <owner>/<repo>
|
|
```
|
|
2. Move the installed skill folder(s) into `ai/config/skills/external/<skill-name>/`. `external/` is core, so both `autumn` and `cloud` consume it. Use `cloud/external/` only if the skill references cloud-only code.
|
|
3. Delete the leftover copies from `.claude/skills/`, `.cursor/skills/`, `.agents/skills/`, `.opencode/skills/` — `bun ai sync` will recreate them as symlinks.
|
|
4. Run `bun ai sync` to symlink the skill into every agent dir across every repo that pulls the `ai/` submodule.
|
|
|
|
## Notes
|
|
|
|
- Skill folder names must be globally unique across `ai/config/skills/**` (sync flattens them).
|
|
- Keep upstream `SKILL.md` frontmatter intact — `name` and `description` drive when the agent loads it. Only edit if the description is not specific enough about WHEN to use the skill.
|
|
- If the skill ships a `references/` or `scripts/` subfolder, copy the whole directory tree, not just `SKILL.md`.
|
|
- Re-running `bunx skills add` upstream-updates: install fresh, diff against `ai/config/skills/external/<name>/`, then promote the changes.
|
|
|
|
# Scope Cache Refresh Changes Safely
|
|
|
|
When changing cache-refresh behavior for API routes:
|
|
|
|
- Prefer editing `server/src/honoMiddlewares/refreshCacheConfigs.ts` to add or remove route entries.
|
|
- Do **not** remove or bypass logic in `server/src/honoMiddlewares/refreshCacheMiddleware.ts` unless the user explicitly asks to change middleware behavior globally.
|
|
- If the request is ambiguous, ask whether they want a route-level config change or a global middleware behavior change.
|
|
|
|
# Cache Version Increment Policy
|
|
|
|
Treat `cache_version` as a DB-side stale-sync guard for `syncItemV4`, not a general cache mutation counter.
|
|
|
|
## Increment cache_version only when needed
|
|
|
|
Increment only for DB updates that must not be overwritten by stale sync payloads read from cache (for example lifecycle or billing transitions).
|
|
|
|
## Do not increment on cache-side/runtime patch paths
|
|
|
|
For runtime balance/reset/cache patch flows, do not bump `cache_version` in cache writers or Lua update scripts.
|
|
|
|
Examples:
|
|
|
|
- FullSubject cache patch helpers (`updateSubjectBalanceCache`, reset/deduction cache patch sync helpers)
|
|
- FullSubject Lua cache update scripts (`updateSubjectBalances`)
|
|
- Update-balance runtime paths that patch Redis and then sync
|
|
|
|
## Call-site rule for CusEntService.update
|
|
|
|
When using `CusEntService.update(...)` in runtime FullSubject cache patch flows, set `incrementCacheVersion` explicitly.
|
|
|
|
- Use `incrementCacheVersion: false` for routine balance/reset/adjustment updates that are mirrored to Redis.
|
|
- Use `incrementCacheVersion: true` only for intentional DB-side stale-write protection transitions.
|
|
|
|
## Why
|
|
|
|
Incorrect version bumps create `CACHE_VERSION_MISMATCH` conflicts in `syncItemV4`, causing repeated invalidation and stale/lost update behavior.
|
|
|
|
## Legacy exception (review-required)
|
|
|
|
There is a legacy-compatibility exception in the adjust-balance flow:
|
|
|
|
- `adjustBalanceDbAndCache` currently uses `CusEntService.increment/decrement`, which increments `cache_version`.
|
|
- Treat this as a reviewable legacy action, not a pattern to copy into new runtime/cache patch paths.
|
|
- Any new or refactored runtime balance/reset/cache patch code should continue following this policy and avoid adding new cache-version bumps by default.
|
|
|
|
## Project Context System
|
|
|
|
Projects maintain state in `.context/<project>/` folders across sessions. Tasks are optional parallel workstreams within a project.
|
|
|
|
### Default: NOT interacting with a project
|
|
**Unless the user explicitly mentions a project or task by name, assume the current conversation is NOT associated with any project.** Session-start hooks may surface a list of active projects as reference material — that alone is NOT a signal that the current work belongs to any of them.
|
|
|
|
Do not:
|
|
- Read `.context/**` files proactively
|
|
- Write, update, or append to any project's STATUS.md / DECISIONS.md / sessions
|
|
- Assume a script, audit, or change is part of a project just because it touches files related to one (e.g. a user-of-framework script is not part of the framework's project)
|
|
|
|
Only engage with `.context/<project>/` when the user explicitly references the project, opens a task in it, or asks for project-tracking actions.
|
|
|
|
### Reading context (when a project IS referenced)
|
|
When the user mentions a project or task name and `.context/<name>/` exists:
|
|
1. Read project STATUS.md first (20-30 line "resume card")
|
|
2. If the project has `tasks/`, list active tasks
|
|
3. If the user mentions a specific task, read `tasks/<task>/STATUS.md`
|
|
4. Read the most recent session summary if more detail is needed
|
|
5. Do NOT read everything upfront. Use progressive disclosure.
|
|
|
|
### Updating context (at breakpoints, NOT continuously)
|
|
Only update when the current work IS part of a project (see default-off rule above). When it is, update at these moments ONLY:
|
|
- Phase or milestone completed
|
|
- Architectural decision made (append to DECISIONS.md)
|
|
- User says they're done or switching tasks
|
|
- Blocker discovered or resolved
|
|
- Task created, completed, or handed off
|
|
|
|
Do NOT update context during normal coding work. Work first, compact at breakpoints.
|
|
|
|
A STATUS.md entry should record changes to the project itself -- not one-off work that merely uses the project (e.g. writing a consumer script of a framework is not a framework-project update).
|
|
|
|
### Compaction quality
|
|
STATUS.md must be:
|
|
- Correct (reflects actual current state, not stale)
|
|
- Complete (no critical information missing)
|
|
- Concise (project < 30 lines, task < 20 lines)
|
|
|
|
Always REWRITE STATUS.md completely rather than append.
|
|
|
|
### File structure
|
|
```
|
|
.context/<project>/
|
|
STATUS.md -- project resume card (includes Active Tasks section)
|
|
PLAN.md -- phases and architecture
|
|
DECISIONS.md -- append-only decision log
|
|
sessions/ -- dated session summaries
|
|
tasks/ -- optional parallel workstreams
|
|
<task>/
|
|
STATUS.md -- task resume card
|
|
DECISIONS.md
|
|
```
|
|
|
|
### Task handoff
|
|
When a task is being handed to another agent, ensure the task's STATUS.md is up to date -- it's the handoff artifact.
|