Skip to content

Commit 4edeb63

Browse files
author
SIN CI
committed
merge: integrate sincode-loop-system-restored branch
Resolved conflicts by keeping main branch versions for shared files.
2 parents 8c94d90 + e3f0f78 commit 4edeb63

6 files changed

Lines changed: 86 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,25 @@ reports them; `debt check` gates them.
534534
rendering drift breaks the build (the prerequisite for issue #168's
535535
ledger-level token-cost hashing).
536536

537+
### Added — SinCode Loop System (always-on Definition-of-Done baseline)
538+
- **Baseline DoD** (`internal/goalcontract/baseline.go`): an always-on
539+
Definition-of-Done that is merged into every resolved contract so the
540+
"self-evident" follow-through work is implicit for every goal — the user
541+
never has to ask an agent to write tests, debug, remove scaffolding, or
542+
update docs again. It adds deterministic predicate checks (tests touched in
543+
the diff, `CHANGELOG.md` touched, a `.doc.md` CoDoc beside each changed Go
544+
file) plus LLM-judged semantic criteria (tests cover new behavior, no debug
545+
leftovers, goal fully addressed, README/CHANGELOG/AGENTS/MASTER_TODO/CoDocs
546+
kept in sync). Additive and deduped against auto-detected/explicit criteria.
547+
- **DoD preamble injection** (`agentloop.Loop.Preamble` + `goalcontract.Preamble`):
548+
the loop now states the rubric to the worker up front via `loopbuilder`, so
549+
tests/debug/docs/completeness are handled on the first pass instead of after
550+
a stop-gate rejection. Advisory only; the stop-gate still enforces.
551+
- **Always-on, globally escapable**: baseline is ON by default in `daemon` and
552+
`auto run`; disable per-invocation with `--no-baseline` or globally with
553+
`SIN_BASELINE=off` (`goalcontract.BaselineEnabled`). Fail-open: predicate
554+
scripts exit 0 outside a git repo so they never wedge a non-repo workspace.
555+
537556
### Added — Loop Engineering (decoupled completion authority)
538557
### Added — MCP tool-manifest compression (issue #173, v3.19.0)
539558
- **`internal/mcpcompress/`** — ponytail-tag compressor for

MASTER_TODO.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,26 @@
144144
---
145145

146146
*Last updated: 2026-06-02*
147+
148+
---
149+
150+
## SinCode Loop System — always-on Definition-of-Done (2026-06-16)
151+
152+
- [x] Baseline DoD module (`internal/goalcontract/baseline.go`) — deterministic
153+
predicate checks (tests touched, CHANGELOG touched, `.doc.md` CoDoc per changed
154+
Go file) + semantic criteria (tests cover new behavior, no debug leftovers,
155+
goal fully addressed, docs in sync).
156+
- [x] Additive, deduped merge into `goalcontract.Resolve` via `IncludeBaseline`.
157+
- [x] DoD preamble injected into the worker prompt (`goalcontract.Preamble`
158+
`agentloop.Loop.Preamble`, wired in `loopbuilder.Build`).
159+
- [x] ON by default in `daemon` and `auto run`; `--no-baseline` / `SIN_BASELINE=off`.
160+
- [x] Tests: `baseline_test.go` (23 cases incl. real-git predicate execution) +
161+
`loop_preamble_test.go`. Docs synced: CHANGELOG, AGENTS.md, CoDocs, this file.
162+
163+
### Follow-ups / backlog
164+
- [ ] Extend baseline predicates beyond Go (per-language test-file detection).
165+
- [ ] Make the CoDoc/CHANGELOG predicates configurable per repo (opt-out subsets).
166+
- [ ] Apply the baseline to interactive surfaces (swarm/serve) once they gain a
167+
completion gate.
168+
169+
*Loop-system update: 2026-06-16*

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ swarm mode, skill bootstrapping, and methodology skills.
6969

7070
**Bounded Autonomy (v3.5.0):** Goal queue + cron/file triggers + skill-lifecycle manager + autonomous daemon. Three hard safety invariants: no gate → no daemon; headless → ask=deny; budget exhausted → hook summons the human.
7171

72+
**SinCode Loop System (always-on Definition-of-Done):** Every goal automatically carries the "self-evident" follow-through — write tests, debug, remove scaffolding, finish the job, and keep `README`/`CHANGELOG`/`AGENTS.md`/`MASTER_TODO`/`.doc.md` CoDocs in sync — so you never have to tell an agent to do that work again. The baseline is merged into every contract, stated to the worker up front, and enforced by the independent stop-gate. ON by default in `daemon` and `auto run`; escape with `--no-baseline` or `SIN_BASELINE=off`.
73+
7274
**Self-Extending (v3.4.0+):** `sin_bootstrap_skill` writes Python MCP servers from natural-language specs, tests them, and deploys them on the fly (defense-in-depth: requires `SIN_ALLOW_BOOTSTRAP=1`).
7375

7476
**Time-Travel Debugging:** Fork any session at any turn to explore parallel solution paths (`sin-code session fork <id> <turn>`).

cmd/sin-code/auto_cmd.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/agentloop"
1818
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/autopilot"
19+
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/goalcontract"
1920
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/lessons"
2021
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/loopbuilder"
2122
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/mcpclient"
@@ -62,6 +63,7 @@ func newAutoInitCmd() *cobra.Command {
6263
func newAutoRunCmd() *cobra.Command {
6364
var verifyCmd string
6465
var budgetMinutes, maxExperiments, maxTurns int
66+
var noBaseline bool
6567
cmd := &cobra.Command{
6668
Use: "run",
6769
Short: "Run the autonomous loop until the budget is exhausted",
@@ -104,6 +106,22 @@ func newAutoRunCmd() *cobra.Command {
104106
}
105107
defer sessStore.Close()
106108

109+
// Resolve the always-on SinCode loop Definition-of-Done once for
110+
// the whole autonomous session: every experiment the autopilot
111+
// runs is held to the same baseline (tests/debug/docs/completeness)
112+
// via the stop-gate, unless --no-baseline / SIN_BASELINE=off.
113+
var autoContract *goalcontract.GoalContract
114+
if c, cerr := goalcontract.Resolve(goalcontract.ResolveOptions{
115+
Workspace: workspace,
116+
VerifyCmd: verifyCmd,
117+
AutoDetect: true,
118+
IncludeBaseline: goalcontract.BaselineEnabled(noBaseline),
119+
}); cerr != nil {
120+
fmt.Fprintf(cmd.ErrOrStderr(), "warn: auto contract resolve failed, continuing without stop-gate: %v\n", cerr)
121+
} else if !c.IsEmpty() {
122+
autoContract = c
123+
}
124+
107125
runGoal := func(ctx context.Context, goal string) (autopilot.LoopResult, string, error) {
108126
sess, err := sessStore.StartOrResume("")
109127
if err != nil {
@@ -116,6 +134,7 @@ func newAutoRunCmd() *cobra.Command {
116134
VerifyMode: "poc",
117135
VerifyCmd: verifyCmd,
118136
Headless: true,
137+
Contract: autoContract,
119138
ToolFactory: func(mgr *mcpclient.Manager) (agentloop.LocalToolFunc, []agentloop.ToolSpec) {
120139
return combinedTool(workspace, mgr), combinedSpecs(mgr)
121140
},
@@ -171,6 +190,7 @@ func newAutoRunCmd() *cobra.Command {
171190
cmd.Flags().IntVar(&budgetMinutes, "budget-minutes", 0, "wall-clock budget (overrides program.md)")
172191
cmd.Flags().IntVar(&maxExperiments, "max-experiments", 0, "experiment cap (overrides program.md)")
173192
cmd.Flags().IntVar(&maxTurns, "max-turns", 60, "max agent turns per experiment")
193+
cmd.Flags().BoolVar(&noBaseline, "no-baseline", false, "disable the always-on SinCode loop baseline (tests/debug/docs/completeness DoD); also via SIN_BASELINE=off")
174194
return cmd
175195
}
176196

cmd/sin-code/internal/automem_cmd_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ func TestOpenAutoMem_Success(t *testing.T) {
1818
tmpDir := t.TempDir()
1919
oldHome := autoMemDefaultHome
2020
oldOpen := autoMemOpen
21+
oldProject := autoMemProject
2122
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
2223
autoMemOpen = auto_mem.Open
24+
autoMemProject = ""
2325
defer func() {
2426
autoMemDefaultHome = oldHome
2527
autoMemOpen = oldOpen
28+
autoMemProject = oldProject
2629
}()
2730

2831
s, proj, err := openAutoMem()
@@ -103,11 +106,14 @@ func TestAutoMem_ListCmd(t *testing.T) {
103106
tmpDir := t.TempDir()
104107
oldHome := autoMemDefaultHome
105108
oldOpen := autoMemOpen
109+
oldProject := autoMemProject
106110
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
107111
autoMemOpen = auto_mem.Open
112+
autoMemProject = ""
108113
defer func() {
109114
autoMemDefaultHome = oldHome
110115
autoMemOpen = oldOpen
116+
autoMemProject = oldProject
111117
}()
112118

113119
out, err := captureAutoMemCmd(t, memAutoListCmd, []string{})
@@ -123,13 +129,16 @@ func TestAutoMem_ListCmdJSON(t *testing.T) {
123129
tmpDir := t.TempDir()
124130
oldHome := autoMemDefaultHome
125131
oldOpen := autoMemOpen
132+
oldProject := autoMemProject
126133
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
127134
autoMemOpen = auto_mem.Open
135+
autoMemProject = ""
128136
oldFormat := autoMemFormat
129137
autoMemFormat = "json"
130138
defer func() {
131139
autoMemDefaultHome = oldHome
132140
autoMemOpen = oldOpen
141+
autoMemProject = oldProject
133142
autoMemFormat = oldFormat
134143
}()
135144

@@ -146,11 +155,14 @@ func TestAutoMem_ShowCmd(t *testing.T) {
146155
tmpDir := t.TempDir()
147156
oldHome := autoMemDefaultHome
148157
oldOpen := autoMemOpen
158+
oldProject := autoMemProject
149159
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
150160
autoMemOpen = auto_mem.Open
161+
autoMemProject = ""
151162
defer func() {
152163
autoMemDefaultHome = oldHome
153164
autoMemOpen = oldOpen
165+
autoMemProject = oldProject
154166
}()
155167

156168
store, _, err := openAutoMem()
@@ -174,11 +186,14 @@ func TestAutoMem_AppendCmd(t *testing.T) {
174186
tmpDir := t.TempDir()
175187
oldHome := autoMemDefaultHome
176188
oldOpen := autoMemOpen
189+
oldProject := autoMemProject
177190
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
178191
autoMemOpen = auto_mem.Open
192+
autoMemProject = ""
179193
defer func() {
180194
autoMemDefaultHome = oldHome
181195
autoMemOpen = oldOpen
196+
autoMemProject = oldProject
182197
}()
183198

184199
out, err := captureAutoMemCmd(t, memAutoAppendCmd, []string{"heading", "body"})
@@ -194,11 +209,14 @@ func TestAutoMem_RmCmd(t *testing.T) {
194209
tmpDir := t.TempDir()
195210
oldHome := autoMemDefaultHome
196211
oldOpen := autoMemOpen
212+
oldProject := autoMemProject
197213
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
198214
autoMemOpen = auto_mem.Open
215+
autoMemProject = ""
199216
defer func() {
200217
autoMemDefaultHome = oldHome
201218
autoMemOpen = oldOpen
219+
autoMemProject = oldProject
202220
}()
203221

204222
store, _, err := openAutoMem()
@@ -222,11 +240,14 @@ func TestAutoMem_GcCmd(t *testing.T) {
222240
tmpDir := t.TempDir()
223241
oldHome := autoMemDefaultHome
224242
oldOpen := autoMemOpen
243+
oldProject := autoMemProject
225244
autoMemDefaultHome = func() (string, error) { return tmpDir, nil }
226245
autoMemOpen = auto_mem.Open
246+
autoMemProject = ""
227247
defer func() {
228248
autoMemDefaultHome = oldHome
229249
autoMemOpen = oldOpen
250+
autoMemProject = oldProject
230251
}()
231252

232253
out, err := captureAutoMemCmd(t, memAutoGcCmd, []string{})

cmd/sin-code/internal/serve_coverage_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ func TestPrintCompressionStats(t *testing.T) {
445445
p := mcpcompress.All()
446446
stats := []mcpcompress.Stats{
447447
{Name: "sin_test", Original: 100, Compressed: 80, BytesSaved: 20, Ratio: 0.2},
448+
{Name: "sin_negative", Original: 50, Compressed: 60, BytesSaved: -10, Ratio: -0.2},
448449
}
449450
printCompressionStats(f, p, stats)
450451

0 commit comments

Comments
 (0)