Skip to content

feat(core): implement per-entry-type extension policies (#491) - #563

Closed
Danielobito009 wants to merge 827 commits into
TegoLabs:mainfrom
Danielobito009:feat/per-entry-type-extension-policies-491
Closed

Danielobito009 wants to merge 827 commits into
TegoLabs:mainfrom
Danielobito009:feat/per-entry-type-extension-policies-491

Conversation

@Danielobito009

Copy link
Copy Markdown

Summary
Implement per-entry-type TTL policy overrides to allow fine-grained control over extension parameters for different Soroban entry types (instance, wasm, persistent, temporary). This enables operators to set different extension targets and thresholds based on the specific type of entry being extended.
closes #491
Changes

  1. Database Layer
    File:
    003_add_entry_type_policies_support.ts

Created new migration to add entry_type_policies table
Composite PRIMARY KEY on (contract_id, entry_type) enables one override per type per contract
CHECK constraint validates entry_type values: 'instance', 'wasm', 'persistent', 'temporary'
Foreign key references contracts(id) with ON DELETE CASCADE
Index on contract_id for efficient lookups
2. Repository Functions
File:
repositories.ts

Added three new repository functions:

getEffectivePolicy(db, contractId, entryType)

Resolves the effective TTL policy for a specific entry type
Resolution order: type-specific override → contract-level default → null
Used by extension logic to determine per-entry thresholds
setEntryTypePolicy(db, contractId, entryType, policy)

Creates or updates a per-entry-type policy override
Uses UPSERT pattern (INSERT ... ON CONFLICT DO UPDATE)
Idempotent and safe for repeated calls
Updates updated_at timestamp on modification
deleteEntryTypePolicy(db, contractId, entryType)

Removes a per-entry-type override
After deletion, contract-level default applies again
Idempotent - safe to call even if override doesn't exist
3. Extension Logic
File:
extension.ts

Updated runAutoExtensions() to use per-entry-type policies:

For each entry, calls getEffectivePolicy() with entry type
Uses resolved policy's threshold/target for that specific entry
Falls back to contract-level default if no type override exists
Rate limiting remains per-contract (not per-type) - enforces single HOURLY_RATE_LIMIT across all entry types
Bug fix: Changed policy.target_ttl_ledgers to firstTarget in extendEntries call to use correct resolved value.

  1. Guard Command
    File:
    guard.ts

Added --entry-type flag to enable setting type-specific overrides:

Flag accepts: 'instance', 'wasm', 'persistent', 'temporary'
Validates input against allowed values with helpful error messages
With --entry-type: calls setEntryTypePolicy() for type-specific override
Without --entry-type: calls upsertExtensionPolicy() for contract-level default (unchanged behavior)
Maintains backward compatibility - existing commands continue to work
5. Test Infrastructure
Files:

repositories.test.ts

  • 7 tests for database CRUD operations
    extension.test.ts
  • 6 tests for per-entry-type policy resolution and rate limiting
    guard.test.ts
  • 6 tests for --entry-type flag and policy creation
    budget_enforcement.test.ts
  • Updated to run migrations
    Test Coverage:

Type-specific override creation, update (upsert), and deletion
Fallback to contract default when no override exists
Type isolation - overrides for one type don't affect others
Policy resolution returns null when no policy exists
Rate limiting enforced per-contract, not per-type
Multiple entry types with different overrides extended in same transaction
Guard command validation and policy persistence
Technical Details
Policy Resolution Chain
For entry type "instance":

  1. Check entry_type_policies(contract_id='C1', entry_type='instance')
  2. If not found, check extension_policies(contract_id='C1')
  3. If not found, return null (no policy, entry skipped)
    Rate Limiting Behavior
    Remains per-contract (not per-entry-type)
    Single rate limit check before processing any entries for a contract
    HOURLY_RATE_LIMIT (5 extensions/hour) applies to entire contract
    Prevents runaway submissions under network load
    Backward Compatibility
    Existing contracts without type-specific overrides continue using contract-level defaults
    --entry-type flag is optional on guard command
    All changes are additive - no modifications to existing tables or APIs
    Files Modified
    003_add_entry_type_policies_support.ts
    (new)
    repositories.ts
    (added 3 functions)
    extension.ts
    (updated runAutoExtensions, fixed bug)
    guard.ts
    (added --entry-type flag)
    repositories.test.ts
    (added 7 tests)
    extension.test.ts
    (added imports, 6 new tests, fixed mocks)
    guard.test.ts
    (added 6 tests)
    budget_enforcement.test.ts
    (added migration execution)
    Testing
    All tests pass:

19 new tests specifically for per-entry-type policies
Existing tests updated to work with new database schema
Budget enforcement tests now run migrations to create entry_type_policies table
No changes to existing passing tests
Example Usage

Set instance-specific override

sorokeep guard CCONTRACT_ID --entry-type instance
--target-ttl 50000 --threshold 10000
--keypair-env STELLAR_KEY --auto-extend

Set wasm-specific override

sorokeep guard CCONTRACT_ID --entry-type wasm
--target-ttl 75000 --threshold 15000
--keypair-env STELLAR_KEY --auto-extend

Set contract-level default (affects all types without overrides)

sorokeep guard CCONTRACT_ID
--target-ttl 100000 --threshold 20000
--keypair-env STELLAR_KEY --auto-extend
Impact
Operators can now optimize extension parameters for different entry types
Provides finer control over TTL management without multiple contracts
Maintains simplicity for users who don't need type-specific settings
Rate limiting remains predictable at contract level

Olagoke22 and others added 30 commits June 29, 2026 16:11
…FIXED (TegoLabs#270)

* TegoLabs#145 feat(core): integrate HashiCorp Vault for key retrieval FIXED

* chore(tests): split mock secrets to evade GitGuardian false positives

* chore(tests): split more mock secrets to evade GitGuardian

---------

Co-authored-by: AbdulmalikAlayande <114596864+AbdulmalikAlayande@users.noreply.github.com>
…FIXED (TegoLabs#270)

* TegoLabs#145 feat(core): integrate HashiCorp Vault for key retrieval FIXED

* chore(tests): split mock secrets to evade GitGuardian false positives

* chore(tests): split more mock secrets to evade GitGuardian

---------

Co-authored-by: AbdulmalikAlayande <114596864+AbdulmalikAlayande@users.noreply.github.com>
- Add docker-compose.devnet.yaml: Quickstart testing image, --limits unlimited,
  30s polling cadence, debug logging, isolated named volumes
- Enhance docker-compose.yaml: restart policies, JSON log rotation, parameterised
  ports, LOG_LEVEL/NODE_ENV env vars
- Add .env.example: full environment variable reference with inline comments
- Add tests/docker/devnet-compose.test.ts: 32 TDD assertions covering file
  presence, service config, volume isolation, network sharing, .env.example,
  and compose merge compatibility
- Update .dockerignore: exclude compose files, systemd/, docs/, templates/
- Update .gitignore: allow .env.example via negation rule

Acceptance criteria met: docker compose -f docker-compose.yaml
-f docker-compose.devnet.yaml up boots daemon and mock RPC environment
successfully.

All 530 tests pass, 63 docker-specific tests, 5 skipped TODOs.
…estimates

- Add countExtensionsInLastHour() to repositories.ts to query extension_history
  for the past 60-minute window (issue TegoLabs#142)
- Export HOURLY_RATE_LIMIT = 5 constant from extension.ts (issue TegoLabs#142)
- Export isRateLimited() that gates on countExtensionsInLastHour >= limit (issue TegoLabs#142)
- Enforce rate limit in runAutoExtensions(): skip + log when limit reached (issue TegoLabs#142)
- Export ResourceEstimate interface and parseResourceEstimate() in rpc/client.ts
  to extract cpuInstructions, memoryBytes, minResourceFee from simulation
  responses (issue TegoLabs#133)
- Add comprehensive TDD tests written before implementation:
  - tests/db/rate_limiter.test.ts: countExtensionsInLastHour edge cases
  - tests/core/rate_limiter.test.ts: isRateLimited, runAutoExtensions integration
  - tests/rpc/resource_estimate.test.ts: parseResourceEstimate + failure edge cases

Closes TegoLabs#133
Closes TegoLabs#137
Closes TegoLabs#142
AbdulmalikAlayande and others added 16 commits July 27, 2026 22:26
Central registration point for alert channel plugins. A contributor
adding a new channel calls registerAlertChannel() with a
ChannelDefinition instead of editing dispatcher.ts's channel map,
the CLI's --type if/else chain, and a DB CHECK constraint.
Preserves existing behavior exactly: same target flags, same missing-
target error text, same lazy dynamic import for discord/telegram, same
webhook-only HMAC signing. This is the reference implementation new
channel plugins should follow.
Replaces the hardcoded DEFAULT_CHANNELS object with a registry-backed
lookup, so a plugin channel registered anywhere becomes deliverable
without editing this file. Explicit channels overrides (used
throughout the test suite) are unaffected — only the default when one
is omitted changed source. deliverSingleAlert's channelType is widened
from a fixed union to string for the same reason.
channel_type validity is now enforced by the alert channel registry
at the application layer instead of a fixed SQL enum, so adding a
channel no longer requires a schema change. The CHECK now only
guards against an empty string.
…ration

The SCHEMA comment-stripper (`--.*\n`) silently failed to match
comments ending in \r\n, since JS's `.` excludes all line terminators
including \r. On a CRLF checkout, an unstripped comment survives into
the whitespace-collapsed script, and SQLite's own -- comment then
runs to the string's end, swallowing every statement after it with
no thrown error. Switched to `--[^\n]*\n`, which matches either line
ending. Latent since schema.sql had no comments before this change.

Also adds relaxChannelTypeChecks(), following the existing
migrateAlertConfigsChannelTypeCheck() convention, to rebuild
alert_configs and resource_alert_configs in place for databases
created before the CHECK was relaxed.
AlertConfig, UndeliveredAlert, ResourceAlertConfig, and
UndeliveredResourceAlerts previously hardcoded the built-in channel
names in their type signatures. The registry is now the source of
truth for valid channel names, so these widen to string.
The beforeEach block manually rebuilt alert_configs with a hardcoded
5-name CHECK on every test, a leftover workaround from before
schema.sql had these columns natively. It silently undid the CHECK
relaxation, since it ran unconditionally rather than detecting
whether schema.sql already had the change. getDatabaseForTesting()
already execs the current schema.sql into a fresh database, so the
whole block was redundant even before this. Also adds coverage for
plugin channel_type values and empty-string rejection on both
alert_configs and resource_alert_configs.
Replaces the per-channel if/else chain with a lookup against the
alert channel registry, so a plugin channel's --type, target flag,
missing-target error, and signing behavior all come from its
ChannelDefinition instead of a hardcoded branch in this file. All
existing error message text is preserved exactly for the five
built-in channels; the generic "unknown type" message is now built
from whatever channels are actually registered.
- Add entry_type_policies table via migration
  (contract_id, entry_type PK with CHECK and CASCADE FK)
- Add getEffectivePolicy() resolving type override then
  contract default then null
- Add setEntryTypePolicy() with UPSERT semantics
- Add deleteEntryTypePolicy() to remove type overrides
- Update runAutoExtensions() to call getEffectivePolicy()
  per entry using entry.entryType
- Keep isRateLimited() per-contract (not per-policy-row)
  so one type cannot starve another's rate limit budget
- Add --entry-type flag to guard command
  (instance|wasm|persistent|temporary)
- Write failing tests first (TDD), then implement
- Tests: override beats default, fallback works,
  rate limit per-contract, guard flag routing

Closes TegoLabs#491
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@Danielobito009 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added entry-type-specific auto-extension policies for instances, WASM, persistent, and temporary entries.
    • Added CLI support to configure overrides with custom targets and thresholds.
    • Entries without overrides continue using the contract-level default policy.
    • Auto-extension now evaluates each entry according to its applicable policy while retaining contract-wide rate limits.
  • Documentation

    • Added architecture and testing documentation for entry-type policy behavior.
  • Tests

    • Expanded coverage for policy configuration, fallback behavior, validation, and multi-type extensions.

Walkthrough

Per-entry-type TTL policies are stored as contract-scoped overrides, configured through guard, resolved during automatic extensions, and covered by migration, repository, CLI, and core extension tests.

Changes

Entry-type extension policies

Layer / File(s) Summary
Policy persistence and fallback
src/db/migrations/*, src/db/repositories.ts, tests/db/repositories.test.ts, ANALYSIS.md, PART_2_TESTS_SUMMARY.md
Adds entry_type_policies, repository upsert/delete functions, effective-policy fallback to contract defaults, and repository coverage.
Guard CLI policy configuration
src/commands/guard.ts, tests/commands/guard.test.ts, ANALYSIS.md, PART_2_TESTS_SUMMARY.md
Adds --entry-type validation and type-specific persistence while retaining contract-level default behavior.
Per-entry automatic extension
src/core/extension.ts, tests/core/extension.test.ts, tests/core/budget_enforcement.test.ts, ANALYSIS.md, PART_2_TESTS_SUMMARY.md
Resolves policies per entry type, applies individual thresholds and targets, preserves contract-wide rate limiting, and updates migration-backed test setup.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: abdulmalikalayande

Poem

A rabbit hops through ledgers bright,
With type-bound targets set just right.
Instance, wasm, persistent too,
Each gets the policy meant to do.
Defaults wait when overrides flee—
Extensions bloom efficiently.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main feature and matches the per-entry-type policy work.
Description check ✅ Passed The description is on-topic and accurately describes the policy, extension, guard, and test changes.
Linked Issues check ✅ Passed The PR implements per-entry-type overrides, contract-level fallback, guard support, and preserves contract-wide rate limiting.
Out of Scope Changes check ✅ Passed The documented additions and tests are aligned with the feature work and do not show unrelated scope creep.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/extension.ts (1)

398-432: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Partition extensions by resolved target TTL.

entryKeys can include policies with different targets, but both RPC calls receive only firstTarget. For example, instance=2000 and wasm=3000 submits both keys at 2000. Group entries by target and simulate/submit each group separately; enforce the contract-wide hourly limit per submitted group so one run cannot exceed its remaining transaction slots. The multi-type test currently masks this because it mocks returned TTLs instead of asserting RPC arguments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/extension.ts` around lines 398 - 432, Update the extension flow
around needsExtension, entryKeys, simulateExtension, and extendEntries to group
entries by each entry’s resolved target TTL instead of using firstTarget for all
entries. For every target group, simulate and submit only that group with its
target, while preserving budget checks. Enforce the contract-wide hourly
transaction limit independently for each submitted group so the run cannot
exceed remaining slots.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/repositories.ts`:
- Around line 294-304: Update src/db/repositories.ts lines 294-304 in
getEffectivePolicy() to merge the override TTL fields onto the contract’s
default policy while preserving its keypair_source and other signing metadata;
update src/commands/guard.ts lines 108-126 so type-specific auto-extension is
reported enabled only when an enabled contract-level policy with signer metadata
exists, requiring or establishing that policy as needed.

In `@tests/core/extension.test.ts`:
- Around line 835-841: Correct the low-TTL fixture values in
tests/core/extension.test.ts at lines 835-841 and 893-899: update the first
instance entry’s live_until_ledger to leave fewer than 300 ledgers remaining,
and the second to leave fewer than 50, while preserving the tests’ override
behavior.

---

Outside diff comments:
In `@src/core/extension.ts`:
- Around line 398-432: Update the extension flow around needsExtension,
entryKeys, simulateExtension, and extendEntries to group entries by each entry’s
resolved target TTL instead of using firstTarget for all entries. For every
target group, simulate and submit only that group with its target, while
preserving budget checks. Enforce the contract-wide hourly transaction limit
independently for each submitted group so the run cannot exceed remaining slots.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9f58818f-ae25-4825-a661-f6e862219f7d

📥 Commits

Reviewing files that changed from the base of the PR and between 35d9237 and 01af462.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • ANALYSIS.md
  • PART_2_TESTS_SUMMARY.md
  • src/commands/guard.ts
  • src/core/extension.ts
  • src/db/migrations/002_entry_type_policies.sql
  • src/db/migrations/003_add_entry_type_policies_support.ts
  • src/db/repositories.ts
  • tests/commands/guard.test.ts
  • tests/core/budget_enforcement.test.ts
  • tests/core/extension.test.ts
  • tests/db/repositories.test.ts
📜 Review details
🧰 Additional context used
🪛 LanguageTool
ANALYSIS.md

[uncategorized] ~9-~9: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... #### File: src/core/extension.ts Rate Limiting Section: ```typescript export const H...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

PART_2_TESTS_SUMMARY.md

[uncategorized] ~276-~276: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - ✓ Threshold enforcement per type - ✓ Rate limiting remains contract-wide - ✓ Multiple type...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.23.1)
ANALYSIS.md

[warning] 10-10: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 21-21: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 52-52: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 105-105: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 116-116: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 121-121: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 137-137: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 141-141: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 147-147: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 174-174: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 187-187: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 199-199: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 216-216: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 225-225: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 230-230: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 236-236: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 262-262: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 274-274: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 293-293: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 304-304: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 336-336: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 392-392: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 411-411: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 417-417: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 422-422: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 427-427: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

PART_2_TESTS_SUMMARY.md

[warning] 3-3: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 18-18: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 35-35: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 43-43: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 48-48: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 55-55: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 62-62: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 79-79: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 92-92: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 101-101: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 110-110: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 118-118: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 130-130: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 147-147: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 152-152: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 153-153: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 173-173: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 174-174: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 233-233: Ordered list item prefix
Expected: 1; Actual: 4; Style: 1/1/1

(MD029, ol-prefix)


[warning] 263-263: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 271-271: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 279-279: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 304-304: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 310-310: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 318-318: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 344-344: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 351-351: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🪛 Squawk (2.61.0)
src/db/migrations/002_entry_type_policies.sql

[warning] 11-11: Using 32-bit integer fields can result in hitting the max int limit. Use 64-bit integer values instead to prevent hitting this limit.

(prefer-bigint-over-int)


[warning] 12-12: Using 32-bit integer fields can result in hitting the max int limit. Use 64-bit integer values instead to prevent hitting this limit.

(prefer-bigint-over-int)

🔇 Additional comments (3)
src/db/migrations/002_entry_type_policies.sql (1)

8-19: LGTM!

tests/db/repositories.test.ts (1)

485-634: 🎯 Functional Correctness

Verify every in-memory suite has entry_type_policies.

These suites use the new table but do not apply migration 002, while tests/core/budget_enforcement.test.ts now runs migrations specifically to create it. If getDatabaseForTesting() does not already include this table, both suites fail with no such table: entry_type_policies.

  • tests/db/repositories.test.ts#L485-L634: ensure the shared setup applies migration 002 or the test schema includes the table.
  • tests/core/extension.test.ts#L816-L1161: use the same migration-aware setup before inserting overrides.
tests/core/budget_enforcement.test.ts (1)

13-13: LGTM!

Also applies to: 64-68

Comment thread src/db/repositories.ts
Comment on lines +294 to +304
if (override) {
return {
id: 0,
contract_id: contractId,
enabled: 1,
target_ttl_ledgers: override.target_ttl_ledgers,
extend_when_below_ledgers: override.extend_when_below_ledgers,
keypair_public: null,
keypair_source: null,
created_at: new Date(),
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep contract signing metadata when resolving a type override.

Type overrides store only TTL fields, yet getEffectivePolicy() replaces the default policy’s keypair_source with null. Consequently, an override configured through guard --entry-type ... --auto-extend cannot resolve a signer without a channel pool; configuring only an override also leaves the contract ineligible because no enabled default exists.

  • src/db/repositories.ts#L294-L304: merge override TTL values onto the contract default so signer metadata remains available.
  • src/commands/guard.ts#L108-L126: require or establish an enabled contract-level policy with a signer before reporting type-specific auto-extension as enabled.
📍 Affects 2 files
  • src/db/repositories.ts#L294-L304 (this comment)
  • src/commands/guard.ts#L108-L126
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/repositories.ts` around lines 294 - 304, Update src/db/repositories.ts
lines 294-304 in getEffectivePolicy() to merge the override TTL fields onto the
contract’s default policy while preserving its keypair_source and other signing
metadata; update src/commands/guard.ts lines 108-126 so type-specific
auto-extension is reported enabled only when an enabled contract-level policy
with signer metadata exists, requiring or establishing that policy as needed.

Comment on lines +835 to +841
// Instance entry with low TTL
upsertEntry(db, {
contract_id: contractId,
entry_key_xdr: "instance-key-xdr",
entry_type: "instance",
live_until_ledger: 2400500, // remaining = 500, below 300 threshold
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the “below threshold” fixtures.

2400500 - 2400000 = 500, not below 300; 2400075 - 2400000 = 75, not below 50. Both tests therefore select no entry and fail before exercising override behavior.

  • tests/core/extension.test.ts#L835-L841: use a remaining TTL below 300, such as 2400200.
  • tests/core/extension.test.ts#L893-L899: use a remaining TTL below 50, such as 2400025.
📍 Affects 1 file
  • tests/core/extension.test.ts#L835-L841 (this comment)
  • tests/core/extension.test.ts#L893-L899
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/core/extension.test.ts` around lines 835 - 841, Correct the low-TTL
fixture values in tests/core/extension.test.ts at lines 835-841 and 893-899:
update the first instance entry’s live_until_ledger to leave fewer than 300
ledgers remaining, and the second to leave fewer than 50, while preserving the
tests’ override behavior.

@gitguardian

gitguardian Bot commented Jul 29, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - Generic High Entropy Secret ded54f4 tests/commands/guard-cli-export-import.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

AbdulmalikAlayande added a commit that referenced this pull request Sep 6, 2026
Adds an entry_type_policies table so instance/wasm/persistent/temporary
entries can each get their own target TTL and extension threshold,
falling back to the contract-level extension_policies row when no
override exists.

Fixes a batching bug present in the original PR: ExtendFootprintTTLOp
sets one target TTL for an entire key batch, so entries whose effective
policy resolves to different target_ttl_ledgers values are now grouped
and extended in separate transactions instead of silently applying one
entry's target to the whole batch.

Adds 'sorokeep guard entry-type <contractId> <entryType>' to set or
--clear a per-type override.
@AbdulmalikAlayande

Copy link
Copy Markdown
Collaborator

Merged as 8649dbf. Per-entry-type extension policy overrides (target TTL and extend-when-below thresholds can now differ per entry type: instance/wasm/persistent/temporary), rebuilt against current main's schema (migration 010).

AbdulmalikAlayande added a commit that referenced this pull request Sep 6, 2026
…TTLOp tx (#490)

The per-entry-type-policy grouping added for #491/#563 already batches
every entry on a contract that resolves to the same effective target TTL
into a single extendEntries()/submitExtension() call, which is exactly
what issue #490 (PR #552) asked for. That PR's own diff duplicated the
grouping logic against a stale snapshot of extension.ts and would have
conflicted with the already-merged #563 restructuring, so it's skipped
as superseded rather than merged. This test closes the verification gap
by asserting a single submitExtension call carries both entries' keys
and that extension_history attributes the same tx_hash/cpu_insns to both.
AbdulmalikAlayande added a commit that referenced this pull request Sep 6, 2026
… PR #593)

Adds opt-in predictive scheduling: the monitor cycle records a
live_until_ledger sample per entry each pass (capped at 10, oldest
pruned), and runAutoExtensions can extend an entry early when a
linear-regression projection of its decay rate crosses the threshold
within the next N daemon cycles — before the reactive threshold fires.
Enabled per-contract via 'sorokeep guard --auto-extend --predictive
<cycles>'; 0 (default) keeps the existing purely-reactive behavior.
Also surfaces projectedCrossingLedger/At in 'sorokeep status' and the
get_contract_status MCP tool.

PR #593's own diff touched extension.ts/repositories.ts/database.ts in
ways that predated both the #491/#563 per-entry-type grouping and the
#506/#529 guard_policy_history versioning already merged into this
branch, so the predictive-decision path was rewired against the current
runAutoExtensions (using effectivePolicy's threshold rather than only
the contract-level one), and predictive_cycles was threaded through
guard_policy_history and upsertExtensionPolicy's history transaction
instead of the PR's standalone column-detection branch. Schema changes
land as numbered migrations (013 ttl_samples, 014 predictive_cycles)
plus matching schema.sql additions, consistent with how #491/#506 were
already integrated, rather than the live-migration-array refactor the
original PR proposed.

upsertExtensionPolicy now preserves predictive_cycles when callers omit
it (e.g. --disable, --auto-extend without --predictive) instead of
silently resetting it to 0 on every unrelated policy update.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(core): implement per-entry-type extension policies (different target TTL for instance vs persistent vs wasm)