Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 39 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
> for lossless Apply; 39 → 40 subcommands. Branch protection on `main`
> permanently relaxed to `required_approving_review_count: 0` for
> solo-maintainer workflow.
> `sin-code debt` (issue #177) — sin-debt marker convention
> (`// sin-debt: <ceiling>, upgrade: <trigger>`) adopted from ponytail;
> 41st subcommand, `cmd/sin-code/internal/sindept/` package with byte-stable
> scanner + aggregator + report + policy gate.

---

Expand Down Expand Up @@ -307,6 +311,12 @@ SIN-Code/
│ │ ├── mcpcompress/ ← v3.19.0: ponytail-tag compressor for `serve --compress-tools`
│ │ ├── install/ ← v3.18.0: pure-stdlib release install + SHA256 verify (issue #170)
│ │ ├── profile/ ← v3.18.0: single-source-of-truth per-agent renderer (issue #175)
│ │ ├── eval/ ← v3.18.0: issue #75 eval + observability
│ │ ├── dataset/ ← v3.18.0: golden-dataset JSON parser
│ │ ├── trace/ ← v3.18.0: OpenTelemetry TracerProvider
│ │ ├── evalharness/ ← v3.18.0: 4-arm comparator (issue #171)
│ │ ├── install/ ← v3.18.0: pure-stdlib install + SHA256 (issue #170)
│ │ ├── sindept/ ← v3.18.0: // sin-debt: marker scanner/reporter (issue #177)
│ │ ├── llm/ ← provider layer
│ │ ├── style/ ← v3.17.0: verbosity / compression mode system-prompt renderer (issue #167)
│ │ ├── orchestrator/ ← DAG, critic, adversary, governor, ...
Expand Down Expand Up @@ -432,6 +442,9 @@ Headless JSON contract (stable API — never break without major bump):
| (next) | TBD | eval/trace infra hardening + first-party golden-dataset CI gate (issue #75 phase 2) |
| v3.19.0 | ✅ SHIPPED | `sin-code serve --compress-tools` (issue #173): ponytail-tag compressor in `internal/mcpcompress/` shrinks the 47-tool manifest on the wire. Tag set `delete|stdlib|native|yagni|shrink`, subset via `--compress-tags`, savings reported via `--print-stats`. Tool names, schemas, and behavior are unchanged (AGENTS.md §10). Closing #173. |

| v3.18.0 | ACTIVE | `sin-code debt` (issue #177) — `// sin-debt: <ceiling>, upgrade: <trigger>` marker convention (ponytail adoption), byte-stable `internal/sindept/` scanner + report, policy gate via `sin-code debt check`, 41st subcommand; alongside `sin-code install` (issue #170), `eval` / `trace` (issue #75), `evalset` / `prp` / `instinct` / `assets` / `hooks` / `rtk` / `codegraph` / `spec` v0 work |
| (next) | TBD | eval/trace infra hardening + first-party golden-dataset CI gate (issue #75 phase 2) |

Each release tag ⇒ goreleaser builds linux/darwin/windows × amd64/arm64,
updates `homebrew-sin` formula, and ships to GitHub Releases.

Expand Down Expand Up @@ -539,6 +552,7 @@ Core: discover, execute, map, grasp, scout, harvest, orchestrate,
Agents: chat, sessions, mcp, goal, daemon, skill, superpowers,
vane, stack, gh, install
vane, stack, gh, install, profile
vane, stack, gh, debt
Frontend: serve, tui, webui
Lifecycle: memory, knowledge, todo, notifications, orchestrator_run,
orchestrator_agents, orchestrator_plan, update
Expand Down Expand Up @@ -583,6 +597,7 @@ same anchor (`SIN-CODE-SKILL`) so a downstream parser finds both
per-skill bundles and per-profile mirrors with one regex. Profile
renders are idempotent (rerun with unchanged source = byte-identical
output), exactly as skilldist demands.
``` (v3.18.0: 41 subcommands — `debt` is issue #177, sin-debt markers; `install` is issue #170; `eval`, `evalset`, `prp`, `instinct`, `assets`, `hooks`, `rtk`, `codegraph`, `spec` follow)

### Hook events (verified `internal/hooks/hooks.go`, v3.5.0)

Expand Down Expand Up @@ -626,6 +641,30 @@ system-prompt hash metric (issue #2).
**Names are immutable.** The 44+ MCP tool `Name` field is public API
(§10). The compressor mutates `Description` only. `CompressSpec`
asserts this in `TestCompressSpec_NameMutable`.
### sin-debt marker convention (issue #177)

Every **intentional** shortcut in source code is marked in-line with:

```
// sin-debt: <ceiling>, upgrade: <trigger>
// sin-debt: <ceiling> # upgrade clause is OPTIONAL but RECOMMENDED
```

- Recognised comment families: `//`, `#`, `--`, `/* … */`, `<!-- … -->`.
- The `upgrade:` clause names the trigger to revisit; markers without it
are **rot-risk** and surface in the `debt stats` rot-risk table.
- Authoring template: prefer the canonical reasons catalogued in
`cmd/sin-code/internal/sindept/policy.go` (`DefaultReasons`) and the
upgrade triggers in `UpgradeTriggers`. Free-form text is allowed;
pick from the catalogue when possible.
- The scanner (`internal/sindept`) and CLI (`sin-code debt`) read this
format; the complexity auditor (issue #179) and audit-engine
(issue #180) recognise it as an "approved shortcut" tag.
- Byte-stable: the same source tree emits byte-identical reports
(`sin-code debt stats`) so the four-arm comparator (issue #171)
can pin its golden snapshot.
- Policy file: `.sin-code/debt-policy.toml` (see
`cmd/sin-code/debt_cmd.doc.md`).

---

Expand Down
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,66 @@ All notable changes to the SIN-Code unified binary will be documented in this fi
contract (golden render, marker-fence idempotency, marker-Fence
covenant, `Verify` pass / missing / drift, write-after-write SHA
equality, replace-not-append for stale mirrors).
### Added — sin-debt marker convention (issue #177)
SIN-Code adopts ponytail v4.7.0's `ponytail:` marker convention as a
first-class, parseable `// sin-debt: <ceiling>, upgrade: <trigger>`
convention. Every intentional shortcut now carries a marker naming its
ceiling and the trigger to revisit; the scanner reads them; `debt stats`
reports them; `debt check` gates them.

- **`internal/sindept/`** — scanner, aggregator, byte-stable report
renderer, and policy gate. Single-package surface:
- `parser.go` — `Marker{File, Line, Column, Reason, Upgrade, HasUpg,
Raw, Language, Symbol}`, regex over five comment families
(`//`, `#`, `--`, `/*…*/`, `<!--…-->`), `ParseFile` + `ParseDir`.
Trims trailing block-comment closers (`*/`, `-->`) and post-processes
captured clauses for byte-determinism.
- `stats.go` — `Stats{Total, WithUpgrade, WithoutUpgrade, ByFile,
ByReason, ByLanguage, BySymbol, RotRisk, Oldest, MarkersPerFile}`.
Every map is materialized as a lex-sorted `[]KV` so `Render*`
output is stable.
- `report.go` — `RenderStats` / `RenderStatsString` /
`RenderListString` markdown renders with `FormatVersion =
"sin-debt/v1"`. Two scans of the same tree emit the same bytes.
- `policy.go` — `Policy{DefaultReasons, UpgradeTriggers,
MaxNoUpgrade, RequireUpgrade, Source}`. TOML overlay via
`.sin-code/debt-policy.toml`; `LoadPolicyForRoot` walks upward to
the closest file.
- **`debt_cmd.go`** — 41st subcommand. `sin-code debt list | stats |
check | policy | fix | export`. Common flags: `--path`, `--format`
(`table|json`), `--no-trigger`. Stats sub-commands take `--by
file|reason|language|symbol|age|summary`. The `check` sub-command
is the CI gate; it exits non-zero when `Missing > MaxNoUpgrade` or
`RequireUpgrade=true && Missing > 0`.
- **`docs/sin-debt-convention.md`** — author-facing reference:
format, examples, default reasons catalogue, default upgrade
triggers.
- **Permitted `sindept__*` tools**: `sindept__list`, `sindept__stats`,
`sindept__policy` are read-only `allow`; `sindept__check` exiting
non-zero is `ask`; `sindept__fix` and `sindept__export` are
`ask` because they instruct humans to edit code or write a file.
- **10 hard-coded fixture markers** under
`cmd/sin-code/internal/sindept/testdata/` (5 languages) and 4 *real*
markers placed in production code (`cmd/sin-code/internal/lessons/
store.go` × 2, `…/ledger/store.go`, `…/orchestrator/dispatcher.go`).
- **Tests**: 23 tests in `cmd/sin-code/internal/sindept/sindept_test.go`
cover family coverage, trailing-closer stripping, byte-stability,
vendor / hidden-dir walk, age/rot grouping, and the
policy-gate semantics above vs. below threshold. Race-clean.

### Notes
- `sin-code debt stats` is the precondition for the four-arm
comparator snapshot (issue #171); byte-stable today, golden file is
expected in the next PR cycle.
- The marker syntax deliberately does NOT include `\Q…\E` quoting —
RE2 has no such construct, and the literal token `sin-debt:` is
plain inside the regex.
- `internal/sindept` is the upstream of issue #179 (complexity auditor)
and issue #180 (audit-engine): both are expected to call
`sindept.ParseFile` / `sindept.AggregateStats` so a marker reads
through the same shape regardless of consumer.

---

### Added — Loop Engineering (decoupled completion authority)
### Added — MCP tool-manifest compression (issue #173, v3.19.0)
Expand Down
113 changes: 113 additions & 0 deletions cmd/sin-code/debt_cmd.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# `sin-code debt` — sin-debt marker manager (issue #177)

Source: `cmd/sin-code/debt_cmd.go`
Package: `cmd/sin-code/internal/sindept/`

## What

`sin-code debt` is the user-facing surface for the **`// sin-debt:` marker
convention** adopted from ponytail v4.7.0 (DietrichGebert/ponytail) and
hardened into SIN-Code as a first-class concept. Every intentional
shortcut in the codebase can (and should) carry a marker naming its
ceiling and the upgrade trigger.

## Subcommands

| Subcommand | Purpose | Exits non-zero on |
|------------|---------|-------------------|
| `list` | One row per marker | nothing (always 0) |
| `stats` | Aggregated report grouped by reason/file/language/symbol/age | nothing |
| `check` | CI gate against the configured policy | rot > threshold OR require_upgrade |
| `policy` | Print the active policy (defaults + on-disk overlay) | nothing |
| `fix` | List rot-risk markers in sed-friendly `path:line\treason` form | nothing |
| `export` | Write the canonical `SIN-DEBT.md` ledger | nothing |

## Common flags

| Flag | Default | Meaning |
|------|---------|---------|
| `--path` | `.` | Root directory or file to scan |
| `--format` | `table` | `table` (markdown) or `json` |
| `--no-trigger` | `false` | When set, returns markers WITHOUT an `upgrade:` clause only |
| `--json` | `false` | Same as `--format=json` (cobra convention) |
| `--by` (stats only) | `file` | `file\|reason\|language\|symbol\|summary\|age` |

## Examples

```bash
# render a markdown report to stdout
sin-code debt list

# show all rot-risk markers
sin-code debt list --no-trigger

# stats grouped by reason (rot + ceiling buckets)
sin-code debt stats --by reason

# chronological — oldest markers first, great for triage Monday morning
sin-code debt stats --by age

# CI gate — exits 1 when more than 50 markers lack an upgrade clause
sin-code debt check

# strict CI gate — exits 1 if ANY marker lacks `upgrade:`
sin-code debt check --require-upgrade

# dump the active policy (defaults merged with the on-disk .sin-code/debt-policy.toml)
sin-code debt policy --json

# write the ledger to ops/backlog/SIN-DEBT.md
sin-code debt export ops/backlog/SIN-DEBT.md
```

## Policy file (`.sin-code/debt-policy.toml`)

```toml
[sin-debt]
max_no_upgrade = 50 # soft ceiling — `check` fails above this
require_upgrade = false # when true, ANY marker without upgrade fails `check`
default_reasons = ["global mutex", "O(n²) scan"]

[sin-debt.upgrade_triggers]
throughput = "when throughput exceeds threshold"
main = "when the upstream API stabilises"
```

The walk looks up the policy from the scan root upwards. The closest
`.sin-code/debt-policy.toml` wins; missing file = out-of-the-box defaults.

## Marker format

```
// sin-debt: <ceiling>, upgrade: <trigger>
// sin-debt: <ceiling> # upgrade is OPTIONAL but RECOMMENDED
```

Reconised comment families: `//`, `#`, `--`, `/* */`, `<!-- -->`.

## Permissions

Registered in `cmd/sin-code/internal/permission_defaults.go`:

| Policy | Layer | Reason |
|--------|-------|--------|
| `sindept__list` | allow | read-only scanner |
| `sindept__stats` | allow | read-only aggregation |
| `sindept__check` | ask | may exit non-zero, visible in CI |
| `sindept__policy` | allow | read-only policy dump |
| `sindept__fix` | ask | outputs patch instructions (manual edit) |
| `sindept__export` | ask | writes SIN-DEBT.md |

## Byte-stability promise

`RenderStatsString` and `RenderListString` are byte-deterministic for
the same `Stats` / marker set. Two scans of the same tree on different
days MUST emit the same bytes — that is the precondition for the
golden-file snapshot that will gate issue #171's four-arm comparator.

## See also

- `docs/sin-debt-convention.md` — author-facing convention + examples
- `cmd/sin-code/internal/sindept/sindept.doc.md` — package-level docs
- Issue #179 — downstream complexity auditor ("approved shortcut" check)
- Issue #180 — audit-engine (`sin-code review --complexity`)
Loading
Loading